From 661d7c7b2e8c8b623272efa58bea96b791e53a33 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 02:35:18 +0100 Subject: [PATCH] Activate paired firing work in the receipt-ordering fixture The queue discovers one concurrent batch at a time; the first HTTP control incorrectly expected another batch to start while the held response was unfinished. Admit both snapshots through the deferred bootstrap owner and then use normal queue activation. Preserve the runtime policy and timeout, and verify each received message explicitly. Change-source: pulse-maintainer --- .../v6/internal/subsystems/notifications.md | 4 ++- .../cooldown_receipt_order_test.go | 29 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/notifications.md b/docs/release-control/v6/internal/subsystems/notifications.md index 1ddb0616ee..2903cb9f5a 100644 --- a/docs/release-control/v6/internal/subsystems/notifications.md +++ b/docs/release-control/v6/internal/subsystems/notifications.md @@ -27,7 +27,9 @@ history. No queue schema, retry budget, recovery selection or schedule changes. `TestNotificationCooldownReceiptOrdering` verifies older, unknown and equal-start completion ordering, including legacy zero starts. The connected `TestLateFiringHTTPReceiptPreservesCurrentCooldown` holds an older HTTP response -while the newer firing completes through the persistent sender. It verifies that +while the newer firing completes through the persistent sender. Both snapshots +are admitted before ordinary queue activation, so one discovered batch can +complete concurrently without adding another dispatcher. It verifies that the ordinary repeat adds no queue row, a current severity increase still reaches the receiver, and both occurrence/destination receipts survive queue reopen. This is loopback source acceptance, not native delivery, restart cooldown diff --git a/internal/notifications/cooldown_receipt_order_test.go b/internal/notifications/cooldown_receipt_order_test.go index 6650194479..d5d3f66c07 100644 --- a/internal/notifications/cooldown_receipt_order_test.go +++ b/internal/notifications/cooldown_receipt_order_test.go @@ -88,7 +88,7 @@ func TestLateFiringHTTPReceiptPreservesCurrentCooldown(t *testing.T) { t.Cleanup(server.Close) dir := t.TempDir() webhook := WebhookConfig{ID: "ops", URL: server.URL + "/hook", Enabled: true, Service: "generic"} - m := NewNotificationManagerWithDataDir("", dir) + m := NewNotificationManagerWithDeferredQueue("", dir) t.Cleanup(m.Stop) t.Cleanup(unblock) // Release an in-flight provider before waiting for shutdown. m.webhookClient = server.Client() @@ -100,16 +100,20 @@ func TestLateFiringHTTPReceiptPreservesCurrentCooldown(t *testing.T) { old := &alerts.Alert{ID: "recurring-cpu", ResourceName: "cpu-node", Type: "cpu", Level: alerts.AlertLevelCritical, Message: "older firing", StartTime: time.Now().UTC().Add(-time.Minute)} m.SendAlert(old) - select { - case <-oldArrived: - case <-time.After(10 * time.Second): - t.Fatal("old firing did not reach the HTTP receiver") - } current := old.Clone() current.StartTime = time.Now().UTC() current.Level = alerts.AlertLevelWarning current.Message = "current warning firing" m.SendAlert(current) + // Workers run concurrently within one discovered batch, but discovery waits + // for that batch to finish. Admit both snapshots before normal activation so + // the HTTP ordering is possible without a second dispatcher or clock edits. + m.StartQueueProcessing() + select { + case <-oldArrived: + case <-time.After(10 * time.Second): + t.Fatal("old firing did not reach the HTTP receiver") + } wait := func(condition func() bool) { t.Helper() deadline := time.Now().Add(10 * time.Second) @@ -147,9 +151,18 @@ func TestLateFiringHTTPReceiptPreservesCurrentCooldown(t *testing.T) { return stats["sent"] == 3 }) mu.Lock() - count := len(bodies) + received := append([]string(nil), bodies...) mu.Unlock() - require.Equal(t, 3, count) + require.Len(t, received, 3) + for _, message := range []string{"older firing", "current warning firing", "current critical firing"} { + count := 0 + for _, body := range received { + if strings.Contains(body, message) { + count++ + } + } + require.Equal(t, 1, count, "receiver must see exactly one %s", message) + } m.Stop() // The old completion still owns a durable recovery receipt, independently // of which occurrence owns the transient repeat-delivery cooldown.