I was pretty comfortable with how async cancellations where done in C# with the TPL, but I am a little bit confused in F#. Apparently by calling Async.CancelDefaultToken()
is enough to cancel outgoing Async<'T>
operations. But they are not cancelled as I expected, they just... vanishes... I cannot detect properly the cancellation and tear down the stack properly.
For example, I have this code that depends on a C# library that uses TPL:
type WebSocketListener with
member x.AsyncAcceptWebSocket = async {
let! client = Async.AwaitTask <| x.AcceptWebSocketAsync Async.DefaultCancellationToken
if(not(isNull client)) then
return Some client
else
return None
}
let rec AsyncAcceptClients(listener : WebSocketListener) =
async {
let! result = listener.AsyncAcceptWebSocket
match result with
| None -> printf "Stop accepting clients.\n"
| Some client ->
Async.Start <| AsyncAcceptMessages client
do! AsyncAcceptClients listener
}
When the CancellationToken
passed to x.AcceptWebSocketAsync
is cancelled, returns null
, and then AsyncAcceptWebSocket
method returns None
. I can verify this with a breakpoint.
But, AsyncAcceptClients
(the caller), never gets that None
value, the method just ends, and "Stop accepting clients.\n"
is never displayed on the console. If I wrap everything in a try\finally
:
let rec AsyncAcceptClients(listener : WebSocketListener) =
async {
try
let! result = listener.AsyncAcceptWebSocket
match result with
| None -> printf "Stop accepting clients.\n"
| Some client ->
Async.Start <| AsyncAcceptMessages client
do! AsyncAcceptClients listener
finally
printf "This message is actually printed"
}
Then what I put in the finally
gets executed when listener.AsyncAcceptWebSocket
returns None
, but the code I have in the match
still doesn't. (Actually, it prints the message on the finally
block once for each connected client, so maybe I should move to an iterative approach?)
However, if I use a custom CancellationToken
rather than Async.DefaultCancellationToken
, everything works as expected, and the "Stop accepting clients.\n"
message is print on screen.
What is going on here?
AcceptWebSocketAsync
is a method declared inside a C# library that accepts aCancellationToken
. When the cancellation is triggered, that method returnsnull
rather than aWebSocket
. This is specifically designed this way. – Melli