// lesson: context-cancellation
Context โ Cancellation, Deadlines, Propagation
Go gives you no way to kill a goroutine. That is deliberate: forcibly
stopping a thread mid-flight leaves locks held and invariants broken, so
cancellation in Go is cooperative โ you ask, the goroutine complies.
context.Context is the standard way to ask.
A context carries three things across API boundaries: a cancellation signal, an optional deadline, and request-scoped values. The signal is a channel, closed exactly once:
ctx, cancel := context.WithTimeout(parent, 2*time.Second)
defer cancel() // always: stops the timer and detaches from the parent
select {
case res := <-work:
return res, nil
case <-ctx.Done():
return nil, ctx.Err() // context.Canceled or context.DeadlineExceeded
}
Contexts form a tree. WithCancel, WithTimeout, and WithDeadline
derive a child from a parent; canceling a parent cancels every
descendant, while canceling a child never affects the parent. This is
what makes the abstraction compose: an HTTP handler's context is
canceled when the client disconnects, and every database call, RPC, and
worker goroutine spawned under it unwinds automatically โ provided each
one actually selects on ctx.Done() while blocking.
Two rules keep this honest. First, ctx is always the first parameter,
never stored in a struct โ it belongs to a call chain, not an object.
Second, if you create a context, you defer cancel() even on success:
until it is canceled (or its deadline fires), a child stays registered
with its parent, keeping its timer and bookkeeping alive longer than
needed โ and anything blocked on its Done channel waits with it.
The pattern you will implement below โ race several attempts, keep the first success, cancel the rest โ is the canonical use of a locally derived cancel: winners cancel losers, without touching the caller's context.
โบ First Result Wins
30 ptsImplement:
func FirstResult(ctx context.Context, fns []func(ctx context.Context) (string, error)) (string, error)
Semantics:
- Run every
fnconcurrently, each receiving a context derived fromctx. - The first
fnto return a nil error wins: return its string and cancel the context passed to the remaining fns, promptly. - If every
fnfails, return a non-nil error (any of the failures is acceptable). - If
ctxis canceled before any success, return promptly with a non-nil error. - If
fnsis empty, return a non-nil error.
FirstResult must not wait for the losers to finish, but the losers
must observe cancellation through their context.
Log in to submit a solution and earn points.