Skip to content
tezvyn:
Menu

Cancellation: Go context vs Rust sync stdlib

Source: interviewHardHow cards are made

Summary

cancellation propagation models.

Key points

Go's context.Context threads a Done channel and deadline through call chains; Rust std has no built-in cancellation, so you wire an AtomicBool or channel and check it.

What's really being asked

Whether you understand cooperative cancellation, that Go bakes it into the standard library via context while Rust's synchronous std leaves it to you, and the limits of interrupting blocked operations.

The full answer

Go's context.Context provides a Done channel that closes on cancel or deadline, an Err describing why, a Deadline, and Value for request-scoped data. You pass ctx as the first parameter through the call chain; handlers select on ctx.Done to bail out, and downstream calls inherit cancellation when you derive children with WithCancel, WithTimeout, or WithDeadline. For graceful shutdown you cancel the root context, and every goroutine observing Done returns. Rust's synchronous std has no context type. You construct your own cancellation signal, commonly an Arc<AtomicBool> set on shutdown, or a channel that workers check between units of work. The challenge is that this is cooperative: a thread already blocked inside a socket read will not notice the flag, so you must also arm a read timeout on the stream so the blocking call returns and the loop can re-check the signal.

The mistakes people make

Claiming Rust std offers context-like cancellation, or that setting an AtomicBool interrupts a blocked Read. Forgetting that Go's cancellation is also cooperative; ctx.Done only helps code that checks it.

What usually comes next

How does this improve under Tokio, where CancellationToken and select! plus future drop give true cancellation of in-flight async work? How do you propagate request IDs without context.Value, perhaps via explicit parameters or thread-locals? How do you drain in-flight requests during shutdown?

A concrete example

Go: ctx, cancel := context.WithCancel(parent); on SIGTERM call cancel(); the handler loop does select { case <-ctx.Done(): return; case work := <-jobs: ... }. Rust std: let stop = Arc::new(AtomicBool::new(false)); the handler loops while not stop.load, with the socket given a read timeout so it periodically wakes to check stop and exit cleanly.

Interview question

Why must a Rust synchronous server pair its custom cancellation flag with a socket read timeout to support graceful shutdown?

  • a.Because setting the flag cannot interrupt a thread already blocked on a socket read, so a timeout lets the loop wake and re-checkCorrect
  • b.Because AtomicBool is not thread-safe without a timeout
  • c.Because read timeouts automatically cancel all running threads
  • d.Because Rust std provides context.Context only when a timeout is set
Why?

Cancellation is cooperative; a blocked read ignores the flag, so a read timeout returns control to the loop to observe the flag. Rust std has no context.Context, and timeouts affect only the one socket operation.

Just read this? Test yourself on what you have been reading.

Read the original → pkg.go.dev

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on go — each one lists the topics its interview covers.

See open roles