Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async.Await not catching Task exception

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?

like image 701
Isaac Abraham Avatar asked Aug 06 '14 17:08

Isaac Abraham


2 Answers

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
        )
like image 75
desco Avatar answered Oct 24 '22 18:10

desco


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
like image 41
N_A Avatar answered Oct 24 '22 17:10

N_A