Question

Go goroutine leak when context cancellation races with channel send

69b6896c-5797-44db-be7e-1ae95cf9b1e6

I have a producer-consumer pattern in Go where a goroutine sends results on a channel. When the parent context is cancelled, the goroutine blocks forever on the channel send because nobody is reading:

func producer(ctx context.Context, ch chan<- Result) {
    for {
        result, err := doWork(ctx)
        if err != nil {
            return
        }
        ch <- result // blocks forever if consumer stopped reading
    }
}

Using select with ctx.Done() helps but there's a race: if the result is ready at the exact moment the context cancels, which case fires? And with buffered channels, is there a risk of the goroutine sending one more item after cancellation? What's the idiomatic way to handle this without leaking?