Files
at-container-registry/pkg
Evan JarrettandClaude Opus 5 05b856bf4e hold/pds: fix two scanner-disconnect panics in the scan broadcaster
Same class of bug as the firehose backfill, plus a second one found alongside
it. Both take down the whole hold process.

1. send on closed channel. Subscribe spawns drainPendingJobs in its own
   goroutine, and it sends to sub.send without holding sb.mu. Unsubscribe
   closed sub.send under the lock, so a scanner disconnecting during the drain
   closed the channel out from under an in-flight send. The existing
   `case <-sub.done` guard did not help: done meant "writer goroutine exited"
   and was closed by handleWriter, which is a different event from
   unsubscribing.

2. close of closed channel. Unsubscribe closed sub.send unconditionally, but
   it is called from two places — handleWriter on write error, and
   handleReader in its defer. A scanner dropping mid-write hits both, and the
   slice-removal loop had no guard, so the second call fell straight through
   to the close. The unassign UPDATE ran twice for the same reason, which
   could return jobs a replacement scanner had already been handed.

sub.send is now never closed. done is repurposed to mean "this subscriber is
gone", closed only by Unsubscribe and guarded on whether the subscriber was
actually still registered. That makes drainPendingJobs' existing done case
correct, and handleWriter selects on done rather than ranging over send.

dispatchJob was already safe — it sends under sb.mu, which excludes
Unsubscribe.

hold01 is unaffected in practice (scanner disabled, no shared secret), but
seamark-hold runs the scanner continuously and is exposed on any scanner
restart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 21:37:40 -05:00
..
2026-05-11 19:53:13 -05:00