簡體   English   中英

異步計算不會捕獲OperationCancelledException

[英]async computation doesn't catch OperationCancelledException

我正在嘗試向URL發出異步Web請求,如果請求耗時太長,將返回該URL。 我正在使用F#異步工作流和System.Net.Http庫來執行此操作。

但是,我無法捕獲async工作流中的System.Net.Http庫引發的Task / OperationCancelledExceptions。 相反,異常是在Async.RunSynchronously方法中引發的,如此堆棧跟蹤中所示:

> 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@()

代碼:

#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

取消總是與錯誤不同。 在您的情況下,您可以覆蓋AwaitTask默認行為,如果取消任務並以不同方式處理它,則調用“取消延續”:

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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM