Cancellation Signals
Cooperative cancellation for asynchronous and long-running work
A cancellation signal is a request for work to stop that does not forcibly terminate the work. The operation must observe the request, release resources, and return or throw at a safe point. Calling a cancel function also does not wait for the operation to finish.
Most cancellation APIs separate authority from observation. The caller owns a controller or cancel function and callees receive a read-only signal or token. This lets a request pass down a call tree without giving every function the power to cancel unrelated work.
Go's Context, .NET's CancellationToken, and the web's AbortSignal all follow this broad pattern.
A good cancellation signal is:
- sticky: once cancelled, it stays cancelled
- composable: a timeout, parent request, or explicit action can share one path
- propagated: every child operation receives the signal
- observable: code can poll it, await it, or register a callback
Consumers must check both before starting and while blocked or looping. A JavaScript API, for example, should reject immediately if its AbortSignal is already aborted, then listen for its abort event while work is pending. CPU-bound work needs explicit checkpoints, as an operation stuck in non-cancellable code cannot respond promptly.
Cancellation is also a result worth preserving. Returning the signal's reason distinguishes a deadline or user abort from an I/O or programming failure. Cleanup belongs in finally, defer, or the language's equivalent, because cancellation can arrive at any suspension or checkpoint.
- Go, context package. ↩
- Microsoft, Cancellation in managed threads. ↩
- MDN, AbortSignal. ↩
Did you enjoy this article?
Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.