This commit is contained in:
ponzischeme89
2026-08-19 06:57:59 +12:00
parent 8c847c59b8
commit 2b43b9ef12
94 changed files with 6359 additions and 778 deletions
+20 -4
View File
@@ -99,9 +99,25 @@ type storedAlert struct {
// Failures are logged and swallowed. A missed banner is not worth failing the thing that
// produced it — an import, a library sync, a health probe — none of which the viewer
// would want retried for the sake of a notice.
//
// Producers no longer call this directly: they call Server.broadcast, which carries the
// same alert through the notification service so it lands in the audit trail beside every
// other thing Memby sent. This remains the delivery half of that path.
func (s *Server) publishAlert(ctx context.Context, alert clientAlert, window time.Duration) {
if err := s.publishAlertNow(ctx, alert, window); err != nil {
s.loggerFor(ctx).Warn("alert publish failed", "id", alert.ID, "error", err)
}
}
// publishAlertNow is publishAlert with the failure returned rather than swallowed.
//
// The notification log needs the error — a banner nobody received is exactly the row an
// operator opens this feature to find — and swallowing it here would leave the audit trail
// reporting a success the cache never gave. Everything above still treats the answer as
// advisory; nothing retries on it.
func (s *Server) publishAlertNow(ctx context.Context, alert clientAlert, window time.Duration) error {
if window <= 0 || alert.ID == "" || s.cache == nil {
return
return nil
}
// Read-modify-write on one key, so producers running on their own schedules need
// serialising against each other. They are rare enough that a mutex is the whole
@@ -113,14 +129,14 @@ func (s *Server) publishAlert(ctx context.Context, alert clientAlert, window tim
stored := appendAlert(s.storedAlerts(ctx), alert, now.Add(window), now)
body, err := json.Marshal(stored)
if err != nil {
s.loggerFor(ctx).Warn("alert encode failed", "error", err)
return
return fmt.Errorf("alert encode failed: %w", err)
}
// The key's own TTL is a floor sweep for a gateway that stops producing events; the
// per-entry expiry is what actually decides what a client sees.
if err := s.cache.Set(ctx, publishedAlertsCacheKey, body, window*2); err != nil {
s.loggerFor(ctx).Warn("alert store failed", "error", err)
return fmt.Errorf("alert store failed: %w", err)
}
return nil
}
// appendAlert is the pure half of publishing: prune what has expired, replace any earlier