Contents

Programming Fundamentals › Concurrency & Async

Cancellation

Stopping in-flight async work cleanly, e.g. with AbortController or a context.

Also known as: abort, cancel, AbortController

Cancellation stops work that’s already running, such as a network request or a background task, because its result is no longer needed. A user navigates away, a request times out, or a newer search replaces an older one. Cancelling frees the resources the work holds and stops it from doing work whose result will be thrown away.

In JavaScript, an AbortController signals a fetch to stop:

const controller = new AbortController();
fetch("/api/search?q=shoes", { signal: controller.signal })
  .then(res => res.json())
  .catch(err => {
    if (err.name === "AbortError") return;   // cancelled on purpose, not a failure
    throw err;
  });

controller.abort();   // e.g. the user typed a new query

In Python’s asyncio, task.cancel() raises CancelledError inside the task at its next await. The task can clean up in a finally block, and must re-raise the error so the cancellation completes.

The trade-off is that cancellation is cooperative. It can only interrupt work at a point where the code is waiting. A tight synchronous loop or a long CPU calculation won’t stop until it returns, and a task that catches the cancellation and carries on ignores it. Cleanup also has to be correct, or half-finished writes are left behind.

The classic mistake is swallowing CancelledError (or the equivalent) in a broad except block, which makes the task refuse to stop. Let cancellation propagate, clean up in finally, and treat a cancelled operation as normal rather than as a failure. For time limits, see coroutines and the wider blocking vs non-blocking model.