任务
对给定的指标序列逐分钟评估阈值规则:只有连续满足持续时长要求时才触发,并报告首次突破发生在哪一分钟。
契约
- 输入:JSON 对象:{ rule: { threshold, comparison, forMinutes }, series: [{ minute, value }] }
- 输出:JSON 对象:{ firing: boolean, firstBreachMinute: number | null }
样例
- 输入
{"rule":{"threshold":0.05,"comparison":"above","forMinutes":3},"series":[{"minute":1,"value":0.01},{"minute":2,"value":0.06},{"minute":3,"value":0.07},{"minute":4,"value":0.08}]}-> 期望{"firing":true,"firstBreachMinute":2}。第 2 到第 4 分钟连续三次突破阈值。 - 输入
{"rule":{"threshold":0.05,"comparison":"above","forMinutes":3},"series":[{"minute":1,"value":0.06},{"minute":2,"value":0.04},{"minute":3,"value":0.06}]}-> 期望{"firing":false,"firstBreachMinute":null}。中间出现一次健康样本使连续计数重置,因此始终没有攒够三次。
参考实现
function solve({ rule, series }) {
const breach = (value) => (rule.comparison === 'above' ? value > rule.threshold : value < rule.threshold);
let streak = 0;
let firstBreachMinute = null;
for (const point of [...series].sort((a, b) => a.minute - b.minute)) {
if (breach(point.value)) {
if (streak === 0) firstBreachMinute = point.minute;
streak += 1;
if (streak >= rule.forMinutes) return { firing: true, firstBreachMinute };
} else {
streak = 0;
firstBreachMinute = null;
}
}
return { firing: false, firstBreachMinute: null };
}
为什么有效
没有持续窗口的告警会因为单个样本就发页。要求连续突破可以滤掉大部分单点噪声,同时仍让真实故障可见。
一个未突破的样本会把连续计数清零,并清空首次突破分钟。