I am looking into a problem where a chain of method calls between various C# async methods and F# async functions is hanging a program. I think the F# script below reproduces the same problem by mixing F# async and TPL:
open System
open System.Threading
open System.Threading.Tasks
let testy = async {
let tokenSource = new CancellationTokenSource();
Task.Run(fun () ->
printfn "Inside first task"
Thread.Sleep(1000)
printfn "First task now cancelling the second task"
tokenSource.Cancel()) |> ignore
let! result =
Task.Factory.StartNew<int>((fun () ->
printfn "Inside second task"
Thread.Sleep(2000)
printfn "Second task about to throw task cancelled exception"
tokenSource.Token.ThrowIfCancellationRequested()
printfn "This is never reached, as expected"
0),
tokenSource.Token)
|> Async.AwaitTask
return result }
printfn "Starting"
let result = testy |> Async.StartAsTask |> Async.AwaitTask |> Async.RunSynchronously
printfn "Program ended with result: %d" result
Running this program in FSI hangs the interpreter. I get the following output before it hangs:
Starting
Inside first task
Inside second task
First task now cancelling the second task
Second task about to throw task cancelled exception
I've discovered that if I change the line
let result = testy |> Async.StartAsTask |> Async.AwaitTask |> Async.RunSynchronously
to
let result = testy |> Async.RunSynchronously
then it no longer hangs and "OperationCanceledException" is shown in the FSI as expected, but I don't know why.