Evaluate a single alert rule: execute aggregate query, check condition per group, feed through hysteresis, dispatch notifications.
(
state: &Arc<SharedState>,
alert: &AlertDef,
hysteresis: &super::hysteresis::HysteresisManager,
now_ms: u64,
)
| 92 | /// Evaluate a single alert rule: execute aggregate query, check condition per group, |
| 93 | /// feed through hysteresis, dispatch notifications. |
| 94 | async fn evaluate_alert( |
| 95 | state: &Arc<SharedState>, |
| 96 | alert: &AlertDef, |
| 97 | hysteresis: &super::hysteresis::HysteresisManager, |
| 98 | now_ms: u64, |
| 99 | ) -> crate::Result<()> { |
| 100 | let tenant_id = TenantId::new(alert.tenant_id); |
| 101 | let window_start = now_ms.saturating_sub(alert.window_ms); |
| 102 | |
| 103 | debug!(alert = alert.name, %window_start, %now_ms, "evaluating alert"); |
| 104 | |
| 105 | // Dispatch aggregate scan directly to Data Plane via SPSC bridge. |
| 106 | let results = |
| 107 | execute_aggregate_scan(state, tenant_id, alert, window_start as i64, now_ms as i64).await?; |
| 108 | |
| 109 | // Process each group's result through hysteresis. |
| 110 | for (group_key, agg_value) in &results { |
| 111 | let condition_met = alert |
| 112 | .condition |
| 113 | .op |
| 114 | .evaluate(*agg_value, alert.condition.threshold); |
| 115 | |
| 116 | let transition = hysteresis.evaluate( |
| 117 | alert.tenant_id, |
| 118 | &alert.name, |
| 119 | group_key, |
| 120 | condition_met, |
| 121 | *agg_value, |
| 122 | alert.fire_after, |
| 123 | alert.recover_after, |
| 124 | now_ms, |
| 125 | ); |
| 126 | |
| 127 | if transition != HysteresisTransition::NoChange { |
| 128 | info!( |
| 129 | alert = alert.name, |
| 130 | group = group_key, |
| 131 | value = agg_value, |
| 132 | threshold = alert.condition.threshold, |
| 133 | transition = ?transition, |
| 134 | "alert state transition" |
| 135 | ); |
| 136 | |
| 137 | dispatch_notifications(state, alert, group_key, *agg_value, transition, now_ms).await; |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | Ok(()) |
| 142 | } |
| 143 | |
| 144 | /// Dispatch an aggregate scan to the Data Plane via the SPSC bridge. |
| 145 | /// |
no test coverage detected