Mission Asyncable - The Basics of Asyncs - Part 1: Cancellation

This post is part of F# Advent Calendar 2020. Check out other posts here.


On my team, we’ve been running into a few microservices stalling and other production issues, due to some nuanced assumptions around Async and cancellations. Knowing the fundamentals is important, and I thought it’d be a useful experience to review them, perhaps from a different angle.


One of the more “invisible” aspects of Async workflows in F# are CancellationTokens. They are constructs that are implicitly passed through Async workflows to enable cooperative cancellation.

Let’s break that down. They’re implicitly passed through in the sense that a parent Async’s CancellationToken is forwarded to child workflows it spawns. By spawns, I mean a child workflow that is handed over control to, usually via let! or do! on an Async<'T> (Note: this propagation can be circumvented, as will be explained below). By cooperative, we mean that a “well-behaved” Async workflow is supposed to inspect the token to see if cancellation’s been requested. It behaves like a good citizen by cancelling the current workflow as quickly as possible, but this is only an expectation, there are no guarantees it will do so.