Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close

    Module 1 · Task lifetimes and cooperative cancellation · Lesson 1 of 6

    Own the task: async completion, exceptions and cancellation

    The problem to solve

    A request starts an asynchronous inventory refresh and returns success before it completes. The refresh later fails, but no caller observes the failure. The central defect is missing ownership: nobody is responsible for awaiting completion, handling failure or stopping the work.

    Mental model

    A Task represents completion, not necessarily a new thread. Awaiting I/O lets the caller yield while the operation is incomplete; it does not make CPU work free. Keep asynchronous call chains asynchronous. Blocking with Result or Wait can consume worker threads and, in some synchronization contexts, deadlock.

    An async method normally executes synchronously until it reaches an incomplete await. Therefore creating many tasks can still perform substantial synchronous work before control returns. Use Task.Run for a deliberate CPU scheduling decision, not as a wrapper around every network call.

    Choose an owner

    For work required to produce the response, await it within the request. For work that must survive the request, persist a job in a durable system and return an accepted/job-status contract. An unawaited task inside a controller is not a durable job queue.

    Use async Task for asynchronous methods whose completion matters. Reserve async void for event-handler signatures that require it; its caller cannot await completion through a Task.

    Cancellation is a request

    The initiator owns a CancellationTokenSource; downstream operations normally receive only its token. Cancellation is cooperative. Passing a token does not stop code that ignores it, and cancellation does not roll back a database commit.

    Illustrative method body:

    C#
    static async Task<int> CountAsync(CancellationToken token)
    {
        int completed = 0;
        for (int i = 0; i < 5; i++)
        {
            token.ThrowIfCancellationRequested();
            await Task.Delay(20, token);
            completed++;
        }
        return completed;
    }

    This sample needs System.Threading and System.Threading.Tasks, supplied by implicit usings in a standard modern console project. The delay models cancellable work; it is not a recommended test synchronization technique.

    Design exercise

    An API commits an order and then the browser disconnects before the response arrives. Should cancellation erase the order? No. Define the commit boundary and provide a way to discover the result, such as an idempotency key or order lookup. The client losing interest is not evidence that the durable operation never happened.

    Check your understanding

    1. Does Task guarantee a dedicated thread? No: it describes completion.
    2. Who disposes a CancellationTokenSource created by this operation? Its owner, after dependent work and registrations no longer need it.
    3. Is fire-and-forget acceptable for a mandatory invoice email? Not without an owned, recoverable background workflow.
    4. Does cancellation guarantee zero side effects? No; inspect the operation contract and commit boundary.

    Interview checkpoint

    Explain the lifetime of the work, who awaits it, how failure is observed and what cancellation means after a side effect. A strong answer names these boundaries before choosing an API.

    Sign in to mark lessons done and keep your place in the course.Sign in