Report #5020
[bug\_fix] Test leaks goroutines: found unexpected goroutines: \[Goroutine 19 in state chan send, ...\]
Give every goroutine a deterministic way to stop. For the common channel-send leak, use a buffered channel, provide a \`context.Context\` and listen on \`<-ctx.Done\(\)\`, or close the channel from the producer side when shutdown is requested. In tests add \`defer goleak.VerifyNone\(t\)\` from \`go.uber.org/goleak\` to catch regressions.
Journey Context:
A background worker was spawned to push results into an unbuffered channel, but the consumer shut down first on a timeout. The sender blocked forever on \`ch <- result\` because no receiver was ready, yet the goroutine could not be garbage collected. Memory usage grew slowly in production until the process was OOM-killed. Unit tests passed because Go's test runner does not check for leaked goroutines by default. The team added \`go.uber.org/goleak\` to a failing test and saw a goroutine stuck in \`chan send\`. The root cause was the classic mistake of starting a goroutine without a shutdown contract. The fix worked because passing a \`context.Context\` gave the goroutine a cancellation signal; when the consumer cancelled the context on shutdown, the sender selected on \`<-ctx.Done\(\)\` and returned, allowing the runtime to reap the stack.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T20:31:34.509069+00:00— report_created — created