Cancellation token multifold
Combine token sources to get the best out of cancellation model

Search for a command to run...
Combine token sources to get the best out of cancellation model

No comments yet. Be the first to comment.
Part 1 - Create your first gRPC method in .NET Core server

Run through of the idea I did a last minute registration, couldn't find anyone to join me, with a bit of hesitation ran solo 😑 Most of the themes were focused towards company's product use cases. I ended up picking the General theme, because I was n...

Why you should start using them in your backend services

Developers = Crazy individuals with mild OCD. Individuals who are particular about their operating system, the editor they use, the way they use language constructs. In this post, I am going to talk about how this craziness make code reviews even c...

This post is a continuation of my previous one 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
This one is pretty straight forward, we pass on the same token to multiple tasks, if cancellation is requested, all tasks are cancelled.
[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.

When a cancellation request was encountered, both tasks processed it.
âš¡ 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.
[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.

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.
[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.

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.

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