I have a Task that does not return anything. You can't do an Async.AwaitTask on such a Task, so you need to do an Async.AwaitIAsyncTask instead. Unfortunately this seems to just swallow any exceptions that the underlying Task throws out: -
TaskFactory().StartNew(Action(fun _ -> failwith "oops"))
|> Async.AwaitIAsyncResult
|> Async.Ignore
|> Async.RunSynchronously
// val it : unit = ()
On the other hand, AwaitTask correctly cascades the exception: -
TaskFactory().StartNew(fun _ -> failwith "oops"
5)
|> Async.AwaitTask
|> Async.Ignore
|> Async.RunSynchronously
// POP!
What's the best way of treating regular (non-generic) Tasks as Async yet still get propagation of exceptions?
As an option that will properly handle cancellation:
open System.Threading.Tasks
module Async =
let AwaitTask (t: Task) =
Async.FromContinuations(fun (s, e, c) ->
t.ContinueWith(fun t ->
if t.IsCompleted then s()
elif t.IsFaulted then e(t.Exception)
else c(System.OperationCanceledException())
)
|> ignore
)
From the Xamarin F# Shirt App (which I originally borrowed from Dave Thomas):
[<AutoOpen>]
module Async =
let inline awaitPlainTask (task: Task) =
// rethrow exception from preceding task if it faulted
let continuation (t : Task) = if t.IsFaulted then raise t.Exception
task.ContinueWith continuation |> Async.AwaitTask
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With