async computation doesn't catch OperationCancelledException

WiseGuyEh

I'm trying to make an asynchronous web request to a URL that will return if the request takes too long. I'm using the F# asynchronous workflow and the System.Net.Http library to do this.

However, I am unable to catch the Task/OperationCancelledExceptions that are raised by the System.Net.Http library in the async workflow. Instead, the exception is raised at the Async.RunSynchronously method, as you can see in this stack trace:

> System.OperationCanceledException: The operation was canceled.    at
> Microsoft.FSharp.Control.AsyncBuilderImpl.commit[a](Result`1 res)   
> at
> Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously[a](CancellationToken
> token, FSharpAsync`1 computation, FSharpOption`1 timeout)    at
> Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1
> computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
> at <StartupCode$FSI_0004>.$FSI_0004.main@()

The code:

#r "System.Net.Http"

open System.Net.Http
open System

let readGoogle () = async {
    try
        let request = new HttpRequestMessage(HttpMethod.Get, "https://google.co.uk")
        let client = new HttpClient()
        client.Timeout <- TimeSpan.FromSeconds(0.01) //intentionally low to always fail in this example
        let! response = client.SendAsync(request, HttpCompletionOption.ResponseContentRead) |> Async.AwaitTask 
        return Some response
    with 
        | ex ->
            //is never called
            printfn "TIMED OUT" 
            return None
}

//exception is raised here
readGoogle ()
    |> Async.RunSynchronously
    |> ignore
desco

Cancellation was always different from the error. In your case you can override default behavior of AwaitTask that invokes "cancel continuation" if task is cancelled and handle it differently:

let readGoogle () = async {
    try
        let request = new HttpRequestMessage(HttpMethod.Get, "https://google.co.uk")
        let client = new HttpClient()
        client.Timeout <- TimeSpan.FromSeconds(0.01) //intentionally low to always fail in this example
        return! ( 
            let t = client.SendAsync(request, HttpCompletionOption.ResponseContentRead)
            Async.FromContinuations(fun (s, e, _) ->
                t.ContinueWith(fun (t: Task<_>) -> 
                    // if task is cancelled treat it as timeout and process on success path
                    if t.IsCanceled then s(None)
                    elif t.IsFaulted then e(t.Exception)
                    else s(Some t.Result)
                )
                |> ignore
            )
        )
    with 
        | ex ->
            //is never called
            printfn "TIMED OUT" 
            return None
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

When catch doesn't actually catch anything

From Dev

Why doesn't catching Exception catch RuntimeException?

From Dev

TRY doesn't CATCH error in BULK INSERT

From Dev

catch/try block doesn't run in Ruby

From Dev

Camel onException doesn't catch NoMessageIdException of idempotentConsumer?

From Dev

@try/@catch doesn't catch exception

From Dev

Why doesn't my code catch Exception?

From Dev

Try/Catch doesn't catch exception

From Dev

Alamofire doesn't catch error

From Dev

Javascript doesn't catch error in WebSocket instantiation

From Dev

TRY...CATCH doesn't seem to work

From Dev

Keyboard accelerator doesn't catch CTRL + A

From Dev

Why doesn't Promise catch error thrown by async operation?

From Dev

MySQL IFNULL() doesn't catch null values

From Dev

Why doesn't the catch statement catch all the exceptions?

From Dev

When catch doesn't actually catch anything

From Dev

@ExceptionHandler doesn't catch HttpMessageNotReadableException

From Dev

Why doesn't the try catch block catch the promise exception?

From Dev

Php remove catch doesn´t work for me

From Dev

Hash doesn't catch if it is nil

From Dev

Catch doesn't execute Toast

From Dev

TRY doesn't CATCH error in BULK INSERT

From Dev

Fiddler doesn't catch downloaders's requests

From Dev

NSView doesn’t catch keyDown events

From Dev

TRY...CATCH doesn't seem to work

From Dev

Try-Catch doesn't catch exception

From Dev

Oracle Doesn't Catch Exception

From Dev

Try-catch doesn't wait for async function inside

From Dev

Promise then doesn't work async?