Cancellation and cleanup: Go context/errgroup vs Tokio
structured-concurrency cancellation knowledge.
Go propagates cancellation via context.Context that goroutines must poll, with errgroup canceling siblings on first error; Tokio cancels by dropping futures, which stops them at await…
WHAT THIS TESTS It examines whether you understand that cancellation in both ecosystems is cooperative, how errors propagate to cancel siblings, and what cleanup guarantees each model offers.
A GOOD ANSWER COVERS In Go, cancellation flows through a context.Context. A parent creates a cancelable context, and child goroutines receive it and must voluntarily check ctx.Done() (often inside select) or pass it to context-aware calls; Go cannot forcibly stop a goroutine, so cancellation is cooperative. errgroup.Group builds structured concurrency on top: you launch goroutines with g.Go, the group is tied to a derived context, the first goroutine to return a non-nil error causes that context to be canceled (signaling the others to wind down), and g.Wait returns the first error. Resource cleanup depends on defer statements and on goroutines actually observing cancellation. In Rust with Tokio, a task is a future; cancellation is achieved by dropping the future. select! polls several futures and, when one completes, drops the others, which stops them at their most recent await point; JoinHandle::abort similarly requests the task be dropped at its next yield. Because dropping a future runs Drop on everything in its stack frame, RAII guards (files, locks, custom Drop) clean up deterministically.
GUARANTEES Go guarantees nothing automatically; cleanup correctness depends on disciplined Done checks and defer. Tokio's drop-based cancellation gives strong RAII cleanup, but only at await points, and code must be cancellation-safe so it is not dropped mid-critical-section leaving inconsistent state.
COMMON WRONG ANSWERS Saying context forcibly kills goroutines. Saying Tokio preempts a task at an arbitrary instruction. Forgetting that both cancel only at cooperative points (Done checks or awaits).
LIKELY FOLLOW-UPS What is cancellation safety in async Rust? Why can a leaked goroutine outlive its context? How does JoinSet or scoped tasks improve structure?
ONE CONCRETE EXAMPLE Fetching from several services: in Go, errgroup launches one goroutine per service sharing a derived context; if one fails, the context is canceled and the others should return promptly when they next check ctx.Done(), and g.Wait surfaces the error. In Tokio, you select! over the futures or spawn tasks and abort the rest on first failure; dropping the losing futures stops them at their next await and runs their destructors to release connections.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.