Alerting: Fix getting targets in dag when using classic condition (#99503)

* fix getting targets in dag when using classic condition

* remove query fingerprinting
the DAG function is probably fast enough and the fingerprinting function is too complex to make it work for all expression types

---------

Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
This commit is contained in:
Sonia Aguilar
2025-01-24 17:45:46 +02:00
committed by GitHub
co-authored by Gilles De Mey
parent 361312bbd7
commit 888965023c
2 changed files with 20 additions and 61 deletions
@@ -2,10 +2,9 @@ import { Graph } from 'app/core/utils/dag';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import {
_createDagFromQueries,
_getDescendants,
_getOriginsOfRefId,
fingerPrintQueries,
createDagFromQueries,
fingerprintGraph,
parseRefsFromMathExpression,
} from './dag';
@@ -45,7 +44,7 @@ describe('working with dag', () => {
},
] as AlertQuery[];
const dag = _createDagFromQueries(queries);
const dag = createDagFromQueries(queries);
expect(Object.keys(dag.nodes)).toHaveLength(4);
@@ -84,9 +83,9 @@ describe('working with dag', () => {
},
] as AlertQuery[];
expect(() => _createDagFromQueries(queries)).not.toThrow();
expect(() => createDagFromQueries(queries)).not.toThrow();
const dag = _createDagFromQueries(queries);
const dag = createDagFromQueries(queries);
expect(Object.keys(dag.nodes)).toHaveLength(1);
@@ -157,36 +156,4 @@ describe('fingerprints', () => {
expect(fingerprintGraph(graph)).toMatchInlineSnapshot(`"A:B: B:C:A, D C::B D:B:"`);
});
test('Queries fingerprint', () => {
const queries = [
{
refId: 'A',
queryType: 'query',
model: {
refId: 'A',
expression: '',
},
},
{
refId: 'B',
queryType: 'query',
model: {
refId: 'B',
expression: 'A',
},
},
{
refId: 'C',
queryType: 'query',
model: {
refId: 'C',
expression: '$B > 0',
type: 'math',
},
},
] as AlertQuery[];
expect(fingerPrintQueries(queries)).toMatchInlineSnapshot(`"Aquery,BAquery,C$B > 0math"`);
});
});
@@ -1,23 +1,15 @@
import { compact, memoize, uniq } from 'lodash';
import memoizeOne from 'memoize-one';
import { Edge, Graph, Node } from 'app/core/utils/dag';
import { isExpressionQuery } from 'app/features/expressions/guards';
import { ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types';
import { AlertQuery } from 'app/types/unified-alerting-dto';
// memoized version of _createDagFromQueries to prevent recreating the DAG if no sources or targets are modified
export const createDagFromQueries = memoizeOne(
_createDagFromQueries,
(previous: Parameters<typeof _createDagFromQueries>, next: Parameters<typeof _createDagFromQueries>) => {
return fingerPrintQueries(previous[0]) === fingerPrintQueries(next[0]);
}
);
/**
* Turn the array of alert queries (this means data queries and expressions)
* in to a DAG, a directed acyclical graph
*/
export function _createDagFromQueries(queries: AlertQuery[]): Graph {
export function createDagFromQueries(queries: AlertQuery[]): Graph {
const graph = new Graph();
const nodes = queries.map((query) => query.refId);
@@ -28,12 +20,9 @@ export function _createDagFromQueries(queries: AlertQuery[]): Graph {
return;
}
const source = query.refId;
const isMathExpression = query.model.type === 'math';
// some expressions have multiple targets (like the math expression)
const targets = isMathExpression
? parseRefsFromMathExpression(query.model.expression ?? '')
: [query.model.expression];
const targets = getTargets(query.model);
targets.forEach((target) => {
const isSelf = source === target;
@@ -47,6 +36,19 @@ export function _createDagFromQueries(queries: AlertQuery[]): Graph {
return graph;
}
function getTargets(model: ExpressionQuery) {
const isMathExpression = model.type === ExpressionQueryType.math;
const isClassicCondition = model.type === ExpressionQueryType.classic;
if (isMathExpression) {
return parseRefsFromMathExpression(model.expression ?? '');
}
if (isClassicCondition) {
return model.conditions?.map((c) => c.query.params[0]) ?? [];
}
return [model.expression];
}
/**
* parse an expression like "$A > $B" or "${FOO BAR} > 0" to an array of refIds
*/
@@ -129,13 +131,3 @@ export function fingerprintGraph(graph: Graph) {
})
.join(' ');
}
// create a unique fingerprint of the array of queries
export function fingerPrintQueries(queries: AlertQuery[]) {
return queries
.map((query) => {
const type = isExpressionQuery(query.model) ? query.model.type : query.queryType;
return query.refId + (query.model.expression ?? '') + type;
})
.join();
}