# Cancellation token multifold

This post is a continuation of my previous one [Cancellation token and APIs](https://blog.kndb.in/cancellation-token-and-apis)😇  

You should check that out for an intro to cancellation tokens and how we can use them in APIs.

In this post we will take a step further and take a look at 
* How to cancel multiple tasks using the same cancellation token
* Link multiple token sources
  1. Track multiple cancellation tokens simultaneously so that we can cancel a task if either token requests cancellation
  2. Parent token, child token scenarios

### Cancel multiple tasks using the same cancellation token
This one is pretty straight forward, we pass on the `same token` to `multiple tasks`, if cancellation is requested, all tasks are cancelled.

```csharp
[HttpPost("~/longoperation")]
public async Task LongRunningOperation(CancellationToken token)
{
    _logger.LogInformation("Calling long running operations");

    Task one = LongRunningOperationOneAsync(token);
    Task two = LongRunningOperationTwoAsync(token);
    await Task.WhenAll(one, two);

    _logger.LogInformation("Done with long running operations");
}

private async Task LongRunningOperationOneAsync(CancellationToken token)
{
    await Task.Delay(1000);
    if (token.IsCancellationRequested)
    {
        _logger.LogError("LongRunningOperationOneAsync was cancelled");
    }
}

private async Task LongRunningOperationTwoAsync(CancellationToken token)
{
    await Task.Delay(1000);
    if (token.IsCancellationRequested)
    {
        _logger.LogError("LongRunningOperationTwoAsync was cancelled");
    }
}
```
After I initiated the request using `Postman`, I immediately hit `cancel` and this is how the application behaves.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638023297523/DvQD8JlzR.png)

When a cancellation request was encountered, both tasks processed it.

### Link multiple token sources
⚡ **Track multiple cancellation tokens simultaneously**  

Leverage `CreateLinkedTokenSource` to combine multiple tokens and build a `CancellationTokenSource`. This tokensource would start monitoring cancellation in any of the encapsulating tokens.

In our case, we created a new CancellationTokenSource and set it up to auto `cancel` after `500ms`, and then we also have the token that is `injected` via the `API request`. We make use of CreateLinkedTokenSource method to generate a new CancellationTokenSource from the 2 tokens, which is then used further in our long running operation.

```csharp
[HttpPost("~/longoperation")]
public async Task LongRunningOperation(CancellationToken token)
{
    CancellationTokenSource otherTokenSource = new CancellationTokenSource();
    otherTokenSource.CancelAfter(500); 

    // create a new tokensource out of available 2 cancellation tokens
    CancellationTokenSource tokenSourceToUse = CancellationTokenSource.CreateLinkedTokenSource(token, otherTokenSource.Token);

    _logger.LogInformation("Calling long running operation");
    await LongRunningOperationOneAsync(tokenSourceToUse.Token);
    _logger.LogInformation("Done with long running operation");
}

private async Task LongRunningOperationOneAsync(CancellationToken token)
{
    await Task.Delay(1000);
    if (token.IsCancellationRequested)
    {
        _logger.LogError("LongRunningOperationOneAsync was cancelled");
    }
}
```
After I initiated the request using `Postman`, I waited for sometime and this is how the application behaves.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638023553887/l3k9EoNKj.png)

Since our token triggers cancellation after `500ms` automatically, our long running operation gets cancelled.

⚡ **Parent token, child token scenarios**  

There are times when you would want to `cancel child tasks` but `continue your parent tasks`. For cases like these, we again leverage an overload of the `CreateLinkedTokenSource` method.

```csharp 
[HttpPost("~/longoperation")]
public async Task LongRunningOperation(CancellationToken parentToken)
{
    // create a tokensource out of parentToken
    CancellationTokenSource childTokenSource = CancellationTokenSource.CreateLinkedTokenSource(parentToken);
    childTokenSource.CancelAfter(500);

    _logger.LogInformation("Calling long running operation");
    await LongRunningOperationOneAsync(childTokenSource.Token);
    if (!parentToken.IsCancellationRequested)
    {
        _logger.LogInformation("Parent cancellation was never requested, continue processing 100 other operations");
    }
    _logger.LogInformation("Done with long running operation");
}

private async Task LongRunningOperationOneAsync(CancellationToken token)
{
    await Task.Delay(1000);
    if (token.IsCancellationRequested)
    {
        _logger.LogError("Child cancellation was requested");
    }
}
```
After I initiated the request using `Postman`, I waited for sometime and this is how the application behaves.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638024731530/wFZUwf2Em.png)

Since our child token triggers cancellation after `500ms` automatically, our child task gets cancelled, but our parent token still continues to be available.

💡 Note
> If parent token is cancelled, all child tokens will be cancelled automatically.

The `Task Parallel Library` provides us with a wide range of easy to use extensions around cancellation tokens, we can setup cancellation behavior for various mix and matches. 

![image](https://media.giphy.com/media/l2JJHgjz1uaEncXew/giphy.gif)

I hope this post gave you some insights on how we can leverage CancellationTokens. Thank you for reading. Cheers!


