[glm-grade=A] fix(monitoring): DC-090 outage incidents follow displayed hysteresis status
checkForIncidents compared raw probe transitions while the dashboard badge (DC-086) follows post-hysteresis displayed status. A single raw down blip between two ups opened AND resolved a critical outage incident; a suppressed up blip during a real outage resolved it early. Incidents now open/resolve on displayed-vs-displayed transitions; previousDisplayed=null keeps legacy raw semantics for direct callers. 6 new parity tests + legacy checkService test moved to a 4-probe chain. Suite 2616/2616 (110). Verdict: urn:ump:yc5rdlnmnmhch5audc5fifgbt6d7moi2stqfs5vidsbh6x6zkvgq
This commit is contained in:
@@ -199,8 +199,9 @@ class HealthChecker extends EventEmitter {
|
||||
}
|
||||
|
||||
const previousStatus = this.currentStatus.get(serviceId);
|
||||
const previousDisplayed = this.displayedStatus.get(serviceId);
|
||||
this.recordStatus(serviceId, status);
|
||||
this.checkForIncidents(serviceId, status, config, previousStatus);
|
||||
this.checkForIncidents(serviceId, status, config, previousStatus, previousDisplayed);
|
||||
|
||||
return status;
|
||||
} catch (error) {
|
||||
@@ -223,8 +224,9 @@ class HealthChecker extends EventEmitter {
|
||||
this.consecutiveFailures.set(serviceId, (this.consecutiveFailures.get(serviceId) || 0) + 1);
|
||||
|
||||
const previousStatus = this.currentStatus.get(serviceId);
|
||||
const previousDisplayed = this.displayedStatus.get(serviceId);
|
||||
this.recordStatus(serviceId, status);
|
||||
this.checkForIncidents(serviceId, status, config, previousStatus);
|
||||
this.checkForIncidents(serviceId, status, config, previousStatus, previousDisplayed);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -453,10 +455,27 @@ class HealthChecker extends EventEmitter {
|
||||
/**
|
||||
* Check for incidents (downtime, slow response, etc.)
|
||||
*/
|
||||
checkForIncidents(serviceId, status, config, previous = this.currentStatus.get(serviceId)) {
|
||||
checkForIncidents(serviceId, status, config, previous = this.currentStatus.get(serviceId), previousDisplayed = null) {
|
||||
|
||||
// Check for status change (up -> down or down -> up)
|
||||
if (previous && previous.status !== status.status) {
|
||||
// DC-090: outage incidents follow the DISPLAYED (post-hysteresis) status —
|
||||
// the same signal that flips the dashboard badge. A single raw "down"
|
||||
// blip that hysteresis suppresses must not open a critical outage
|
||||
// incident (and a suppressed blip must not resolve a real one). When the
|
||||
// caller supplies the pre-probe displayed state (checkService always
|
||||
// does), transitions are evaluated displayed-vs-displayed using the
|
||||
// post-recordStatus state in this.displayedStatus. Direct callers with
|
||||
// no hysteresis state (previousDisplayed === null) keep the legacy
|
||||
// raw-probe transition semantics.
|
||||
if (previousDisplayed) {
|
||||
const displayed = this.displayedStatus.get(serviceId);
|
||||
if (displayed && displayed.status !== previousDisplayed.status) {
|
||||
if (displayed.status === 'down') {
|
||||
this.createIncident(serviceId, 'outage', 'Service is down', displayed);
|
||||
} else if (displayed.status === 'up') {
|
||||
this.resolveIncident(serviceId, 'outage', displayed);
|
||||
}
|
||||
}
|
||||
} else if (previous && previous.status !== status.status) {
|
||||
if (status.status === 'down') {
|
||||
this.createIncident(serviceId, 'outage', 'Service is down', status);
|
||||
} else if (status.status === 'up') {
|
||||
|
||||
Reference in New Issue
Block a user