fix(alerting): allow multiple open alert_instances per rule for PER_EXCHANGE
V13 added a partial unique index on alert_instances(rule_id) WHERE state
IN (PENDING,FIRING,ACKNOWLEDGED). Correct for scalar condition kinds
(ROUTE_METRIC / AGENT_STATE / DEPLOYMENT_STATE / LOG_PATTERN / JVM_METRIC
/ EXCHANGE_MATCH in COUNT_IN_WINDOW) but wrong for EXCHANGE_MATCH /
PER_EXCHANGE, which by design emits one alert_instance per matching
exchange. Under V13 every PER_EXCHANGE tick with >1 match logged
"Skipped duplicate open alert_instance for rule …" at evaluator cadence
and silently lost alert fidelity — only the first matching exchange per
tick got an AlertInstance + webhook dispatch.
V15 drops the rule_id-only constraint and recreates it with a
discriminator on context->'exchange'->>'id'. Scalar kinds emit
Map.of() as context, so their expression resolves to '' — "one open per
rule" preserved. ExchangeMatchEvaluator.evaluatePerExchange always
populates exchange.id, so per-exchange instances coexist cleanly.
Two new PostgresAlertInstanceRepositoryIT tests:
- multiple open instances for same rule + distinct exchanges all land
- second open for identical (rule, exchange) still dedups via the
DuplicateKeyException fallback in save() — defense-in-depth kept
Also fixes pre-existing PostgresAlertReadRepositoryIT brokenness: its
setup() inserted 3 open instances sharing one rule_id, which V13 blocked
on arrival. Migrate to one rule_id per instance (pattern already used
across other storage ITs).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
-- V15 — Discriminate open-alert_instance uniqueness by exchange id for PER_EXCHANGE rules.
|
||||
--
|
||||
-- V13 enforced "one open alert_instance per rule" via a partial unique on
|
||||
-- (rule_id). That is correct for every scalar condition kind (ROUTE_METRIC,
|
||||
-- AGENT_STATE, DEPLOYMENT_STATE, LOG_PATTERN, JVM_METRIC, and EXCHANGE_MATCH
|
||||
-- in COUNT_IN_WINDOW mode) but wrong for EXCHANGE_MATCH / PER_EXCHANGE, which
|
||||
-- by design emits one alert_instance per matching exchange. Under V13 every
|
||||
-- PER_EXCHANGE tick with >1 match logged "Skipped duplicate open alert_instance
|
||||
-- for rule …" at evaluator cadence and silently lost alert fidelity — only the
|
||||
-- first matching exchange per tick got an AlertInstance + webhook dispatch.
|
||||
--
|
||||
-- New discriminator: (rule_id, COALESCE(context->'exchange'->>'id', '')).
|
||||
-- Scalar evaluators emit Map.of() (no exchange subtree), the expression
|
||||
-- resolves to '' for all of them, so they continue to get "one open per rule".
|
||||
-- ExchangeMatchEvaluator.evaluatePerExchange emits {exchange.id = <execId>}
|
||||
-- per firing, so PER_EXCHANGE instances for distinct exchanges coexist.
|
||||
-- Two attempts to open an instance for the same (rule, exchange) still collapse
|
||||
-- to one — the repo's DuplicateKeyException fallback preserves defense-in-depth.
|
||||
DROP INDEX IF EXISTS alert_instances_open_rule_uq;
|
||||
|
||||
CREATE UNIQUE INDEX alert_instances_open_rule_uq
|
||||
ON alert_instances (rule_id, (COALESCE(context->'exchange'->>'id', '')))
|
||||
WHERE rule_id IS NOT NULL
|
||||
AND state IN ('PENDING','FIRING','ACKNOWLEDGED');
|
||||
Reference in New Issue
Block a user