FSharp.Control.AsyncSeq
FSharp.Control.AsyncSeq copied to clipboard
iterAsyncParallel and iterAsyncParallelThrottled may fail to cancel
Description
iterAsyncParallel and iterAsyncParallelThrottled may fail to cancel; this can be observed when exceptions are thrown from another Async in Async.Parallel.
Repro steps
Execute the following code snippet
let r = Random()
let handle x = async {
do! Async.Sleep (r.Next(200))
printfn "%A" x
}
let fakeAsync = async {
do! Async.Sleep 500
return "hello"
}
let makeAsyncSeqBatch () =
let rec loop() = asyncSeq {
let! batch = fakeAsync |> Async.Catch
match batch with
| Choice1Of2 batch ->
if (Seq.isEmpty batch) then
do! Async.Sleep 500
yield! loop()
else
yield batch
yield! loop()
| Choice2Of2 err ->
printfn "Problem getting batch: %A" err
}
loop()
let x = makeAsyncSeqBatch () |> AsyncSeq.concatSeq |> AsyncSeq.iterAsyncParallel handle
let exAsync = async {
do! Async.Sleep 2000
failwith "error"
}
[x; exAsync] |> Async.Parallel |> Async.Ignore |> Async.RunSynchronously
When exAsync throws, Async.Parallel will attempt to cancel the iteration of the AsyncSeq before it returns. iterAsyncParallel and iterAsyncParalleThrottled will sometimes not return and continue running forever. Changing to iterAsync always stops the iteration of the AsyncSeq reliably.
Known workarounds
Don't use iterAsyncParallel or iterAsyncParalleThrottled, use iterAsync instead.
Related information
- Operating system Windows
- Branch 2.0.21
- .NET Runtime, CoreCLR or Mono Version .NET Core 3.1