C#: Cancellation Tokens and Timeouts in Reliable Applications

Introduction

Applications often perform work that users no longer need. A browser request may be abandoned, a scheduled operation may be stopped, or a service may exceed its deadline while waiting for another system.

Cancellation tokens provide a standard way to signal that work should stop. Used consistently, they help applications release resources and avoid wasting effort on operations whose results are no longer needed.

1. Accept cancellation at application boundaries

In ASP.NET Core, an endpoint can receive a cancellation token representing the request’s cancellation signal:

app.MapGet(
    "/products/{id:int}",
    async (
        int id,
        IProductRepository repository,
        CancellationToken cancellationToken) =>
    {
        var product = await repository.GetByIdAsync(
            id,
            cancellationToken);

        return product is null
            ? Results.NotFound()
            : Results.Ok(product);
    });

This example assumes the repository supports asynchronous access and accepts a cancellation token.

Passing the token down through the call chain gives database and network operations a chance to stop when the request is cancelled.

2. Propagate cancellation to downstream calls

A common mistake is accepting a cancellation token but never passing it to the operation that does the work.

For example, a service should propagate the token to HTTP calls, database operations, and other APIs that support cancellation.

public sealed class CatalogClient(HttpClient httpClient)
{
    public async Task<string> GetCatalogAsync(
        CancellationToken cancellationToken)
    {
        using var response = await httpClient.GetAsync(
            "/catalog",
            cancellationToken);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsStringAsync(
            cancellationToken);
    }
}

The token-aware overloads allow the operation to respond to cancellation. Cancellation remains cooperative: a library or remote service may not stop immediately.

3. Distinguish cancellation from failure

Cancellation does not always indicate a system fault. A user may have navigated away, or an upstream operation may have cancelled work that was no longer needed.

Avoid logging every cancellation as a critical error. At the same time, do not swallow all exceptions and label them cancellation. Preserve the distinction between expected cancellation, timeouts, and genuine failures.

4. Apply deadlines deliberately

A cancellation token can be combined with a timeout:

using var timeoutCts =
    new CancellationTokenSource(TimeSpan.FromSeconds(5));

using var linkedCts =
    CancellationTokenSource.CreateLinkedTokenSource(
        requestCancellationToken,
        timeoutCts.Token);

var result = await client.GetCatalogAsync(
    linkedCts.Token);

This example assumes requestCancellationToken is supplied by the calling operation. The linked token is cancelled if either the caller cancels or the five-second timeout expires.

Choose timeouts according to the operation’s purpose and downstream service expectations. A timeout that is too short can cause unnecessary failures; one that is too long can consume resources while a dependency is unhealthy.

5. Do not confuse cancellation with rollback

Cancelling a request does not guarantee that an operation already performed by a remote system is undone.

If a payment request reaches a payment provider before cancellation, the payment may still succeed. Such workflows require explicit operation tracking, idempotency, and reconciliation rather than relying on cancellation alone.

6. Test cancellation behavior

Test that tokens reach the relevant dependencies and that resources are released correctly. Include scenarios where cancellation occurs before work starts, while waiting for I/O, and after a downstream operation has already completed.

Conclusion

Cancellation tokens make it possible to stop unnecessary work and enforce operation deadlines. Accept tokens at the boundaries of your application, propagate them to downstream operations, and design side-effecting workflows with the understanding that cancellation does not reverse completed work.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *