fix: shutdown ends the live-event streams so a redeploy drains instead of waiting out its deadline (#5293)
release / govulncheck (push) Successful in 24s
release / web (push) Successful in 1m49s
release / go (push) Successful in 2m3s
release / integration (push) Successful in 6m1s
release / android (push) Successful in 6m25s
release / Build signed APK (releases and dev) (push) Successful in 6m24s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped

http.Server.Shutdown waits for in-flight requests but never cancels them,
and an SSE stream only ends when its client leaves, so any open tab or
signed-in phone held every redeploy for the full 10s and the old task
exited 1. With the swarm's stop-first update that was ~10s of downtime per
deploy. The bus now closes on shutdown, ending each stream; clients
reconnect to the next instance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 06:46:18 -04:00
co-authored by Claude Opus 5.5
parent fefc51439e
commit 79b90bda03
4 changed files with 71 additions and 1 deletions
+41
View File
@@ -148,3 +148,44 @@ func TestPublish_ConcurrentWritersAndSubscribers(t *testing.T) {
}
subWG.Wait()
}
// Close is what lets the server shut down with SSE clients connected: each
// stream returns when its channel closes (#5293).
func TestClose_EndsEverySubscription(t *testing.T) {
t.Parallel()
b := New()
ch1, unsub1 := b.Subscribe(4)
ch2, unsub2 := b.Subscribe(4)
b.Close()
for i, ch := range []<-chan Event{ch1, ch2} {
if _, ok := <-ch; ok {
t.Fatalf("subscriber %d: channel still open after Close", i)
}
}
if got := b.SubscriberCount(); got != 0 {
t.Fatalf("SubscriberCount=%d after Close, want 0", got)
}
// The handlers' deferred unsubscribes still run; they must not
// double-close.
unsub1()
unsub2()
b.Close()
}
func TestSubscribe_AfterCloseIsAlreadyClosed(t *testing.T) {
t.Parallel()
b := New()
b.Close()
ch, unsub := b.Subscribe(4)
defer unsub()
if _, ok := <-ch; ok {
t.Fatal("a subscription made after Close should already be closed")
}
if got := b.SubscriberCount(); got != 0 {
t.Fatalf("SubscriberCount=%d, want 0", got)
}
b.Publish(Event{Kind: "after.close"}) // must not panic
}