fix
Build and Publish / Metadata (push) Successful in 10s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 2m36s

This commit is contained in:
developer committed 2026-09-24 13:26:24 +00:00
1 parent 49c6c6cc76
commit 6dc2785f71
4 files changed
+117 -24

No files matched your search

+32 -6
View File
@@ -7,7 +7,8 @@
// A pattern shows as PAGED when this tick would have sent a notification
// (new or escalated past its cooldown) and as ongoing while it is still
// firing but already paged once. When a service's spike disappears it is
// reported as recovered for that scan.
// reported as recovered for that scan, and the last firing issue stays on
// the display as resolved until something fires again.
package main
import (
@@ -96,6 +97,12 @@ type scanner struct {
// firing; it mirrors what a person watching notifications would remember.
active map[string]time.Time
// lastActive is the most recent firing issue set; when a later scan
// finds nothing firing, it is kept on the display as resolved instead
// of flipping to ALL CLEAR.
lastActive []issueView
resolvedAt time.Time // window end when lastActive stopped firing
since time.Time
sinceAt time.Time
}
@@ -121,10 +128,11 @@ func newClickHouseScanner(addr, database, user, password string, cfg features.Sp
// issueView is one card on the dashboard: a firing spike reduced to an Alert
// (the same model the notifications carry) plus display state.
type issueView struct {
alert alerts.Alert
key string
paged bool // this scan would have notified (new or escalated)
firstSeen time.Time // window end when this issue first appeared
alert alerts.Alert
key string
paged bool // this scan would have notified (new or escalated)
firstSeen time.Time // window end when this issue first appeared
resolvedAt time.Time // window end when it stopped firing; renders as resolved
}
// recoveredIssue is an issue that fired on the previous scan but not now.
@@ -134,7 +142,8 @@ type recoveredIssue struct {
LastSeen time.Time
}
// snapshot is one scan's result: everything firing right now.
// snapshot is one scan's result: everything firing right now, plus the last
// firing issue kept as resolved when nothing fires any more.
type snapshot struct {
ScannedAt time.Time
WindowEnd time.Time
@@ -142,6 +151,7 @@ type snapshot struct {
Events int
Issues []issueView
Recovered []recoveredIssue
Resolved []issueView
Err error
}
@@ -219,6 +229,22 @@ func (s *scanner) Scan(ctx context.Context, now time.Time) snapshot {
snap.Recovered = append(snap.Recovered, recoveredIssue{Service: serviceOfKey(key), FirstSeen: first, LastSeen: end})
}
}
// Keep the last firing issue on the display: once nothing fires any
// more, the cards stay up as resolved rather than the dashboard erasing
// the context with an ALL CLEAR panel.
if len(snap.Issues) > 0 {
s.lastActive = snap.Issues
s.resolvedAt = time.Time{}
} else if len(s.lastActive) > 0 {
if s.resolvedAt.IsZero() {
s.resolvedAt = end
}
for _, v := range s.lastActive {
v.resolvedAt = s.resolvedAt
snap.Resolved = append(snap.Resolved, v)
}
sortIssues(snap.Resolved)
}
sortIssues(snap.Issues)
return snap
}