Prometheus: Don't use incremental querying if one of the queries has $__range variable (#108823)

don't use incremental querying if one of the queries has $__range variable
This commit is contained in:
ismail simsek 2025-08-01 10:13:49 +02:00 committed by GitHub
parent 8e1b3338c6
commit 63cc91face
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 77 additions and 7 deletions

View File

@ -19,6 +19,7 @@ import { config, getBackendSrv, setBackendSrv, TemplateSrv } from '@grafana/runt
import { extractResourceMatcher, extractRuleMappingFromGroups, PrometheusDatasource } from './datasource';
import { prometheusRegularEscape, prometheusSpecialRegexEscape } from './escaping';
import { PrometheusLanguageProviderInterface } from './language_provider';
import { CacheRequestInfo } from './querycache/QueryCache';
import {
createDataRequest,
createDefaultPromResponse,
@ -1253,3 +1254,72 @@ describe('modifyQuery', () => {
});
});
});
describe('PrometheusDatasource incremental query logic', () => {
let ds: PrometheusDatasource;
let mockCache: {
requestInfo: jest.MockedFunction<(request: DataQueryRequest<PromQuery>) => CacheRequestInfo<PromQuery>>;
procFrames: jest.MockedFunction<(...args: unknown[]) => unknown[]>;
};
beforeEach(() => {
jest.clearAllMocks();
mockCache = {
requestInfo: jest.fn().mockReturnValue({
requests: [{ targets: [], range: getMockTimeRange() }],
targetSignatures: new Map(),
shouldCache: true,
}),
procFrames: jest.fn().mockReturnValue([]),
};
const incrementalInstanceSettings = {
url: 'proxied',
id: 1,
uid: 'ABCDEF',
access: 'proxy',
user: 'test',
password: 'mupp',
jsonData: {
customQueryParameters: '',
cacheLevel: PrometheusCacheLevel.Low,
incrementalQuerying: true,
} as Partial<PromOptions>,
} as unknown as DataSourceInstanceSettings<PromOptions>;
ds = new PrometheusDatasource(incrementalInstanceSettings, templateSrvStub);
ds.cache = mockCache as unknown as typeof ds.cache;
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should use incremental query for normal queries when incrementalQuerying is true', async () => {
const request = createDataRequest([{ expr: 'up', refId: 'A' }]);
await lastValueFrom(ds.query(request));
expect(mockCache.requestInfo).toHaveBeenCalled();
});
it('should disable incremental query when query contains $__range', async () => {
const request = createDataRequest([{ expr: 'rate(up[$__range])', refId: 'A' }]);
await lastValueFrom(ds.query(request));
expect(mockCache.requestInfo).not.toHaveBeenCalled();
});
it('should disable incremental query when any target contains $__range', async () => {
const request = createDataRequest([
{ expr: 'up', refId: 'A' },
{ expr: 'rate(cpu[$__range])', refId: 'B' },
]);
await lastValueFrom(ds.query(request));
expect(mockCache.requestInfo).not.toHaveBeenCalled();
});
it('should disable incremental query for instant queries', async () => {
const request = createDataRequest([{ expr: 'up', refId: 'A', instant: true }]);
await lastValueFrom(ds.query(request));
expect(mockCache.requestInfo).not.toHaveBeenCalled();
});
});

View File

@ -492,16 +492,16 @@ export class PrometheusDatasource
return this.directAccessError();
}
let fullOrPartialRequest: DataQueryRequest<PromQuery>;
let requestInfo: CacheRequestInfo<PromQuery> | undefined = undefined;
const hasInstantQuery = request.targets.some((target) => target.instant);
// Use incremental query only if enabled and no instant queries or no $__range variables
const shouldUseIncrementalQuery =
this.hasIncrementalQuery && !request.targets.some((target) => target.instant || target.expr.includes('$__range'));
// Don't cache instant queries
if (this.hasIncrementalQuery && !hasInstantQuery) {
let fullOrPartialRequest: DataQueryRequest<PromQuery> = request;
let requestInfo: CacheRequestInfo<PromQuery> | undefined = undefined;
if (shouldUseIncrementalQuery) {
requestInfo = this.cache.requestInfo(request);
fullOrPartialRequest = requestInfo.requests[0];
} else {
fullOrPartialRequest = request;
}
const targets = fullOrPartialRequest.targets.map((target) => this.processTargetV2(target, fullOrPartialRequest));