A report the store cannot take yet is handed back to the broker, not acknowledged and lost (novox/hq issue 082)

This commit is contained in:
2026-09-22 13:25:13 +02:00
parent ff26ea959d
commit 047830a6b5
5 changed files with 157 additions and 1 deletions
+25
View File
@@ -52,8 +52,20 @@ type Server struct {
log *log.Logger
upgrader Upgrader
replayer Replayer
// again is how long a report the store could not take waits before it is handed back to
// the broker; zero means TryAgainAfter.
again time.Duration
}
// ErrTryAgain marks a listener's failure as "not now": what it was given is worth keeping and
// asking again, as when the store is restarting (novox/hq issue 082).
var ErrTryAgain = errors.New("not now, try again")
// TryAgainAfter is the pause before a report the store could not take goes back to the broker.
// The consumer takes one message at a time, so without it a restarting store would be asked in
// a tight loop; a store comes back in seconds, and a report a few seconds late is still current.
const TryAgainAfter = 2 * time.Second
// Records tells the server where to keep build results.
//
// Set after Connect rather than passed to it, because a control plane that only publishes — the
@@ -311,6 +323,19 @@ func (s *Server) handleReport(delivery amqp.Delivery) {
}
if s.listener != nil {
if err := s.listener.Heard(context.Background(), report); err != nil {
if errors.Is(err, ErrTryAgain) {
// Kept, not acknowledged. The node reports an apply once, and a report lost here
// is a node the mesh never hears from again: the store restarting under the
// adoption that node just applied lost exactly that (novox/hq issue 082).
again := s.again
if again == 0 {
again = TryAgainAfter
}
s.log.Printf("could not record %s's report yet, and will again in %s: %v", report.Node, again, err)
time.Sleep(again)
_ = delivery.Nack(false, true)
return
}
// Said rather than swallowed. A report the mesh heard and failed to write down is a
// node whose recovery copy is silently older than it looks.
s.log.Printf("could not record %s's report: %v", report.Node, err)