【问题标题】:Catching HttpClient timeouts within an async workflow在异步工作流中捕获 HttpClient 超时
【发布时间】:2016-05-09 09:55:07
【问题描述】:

我通过Async.AwaitTask 呼叫HttpClient,是从代理(邮箱处理器)内部调用的。我想在 HTTP 调用期间捕获错误,因此在异步工作流程中使用了 try...with,但它完全错过了捕获客户端超时异常,然后导致代理崩溃。

最小复制:

#r "System.Net.Http"
open System
open System.Net.Http

let client = new HttpClient()
client.Timeout <- TimeSpan.FromSeconds(1.)
async {
    try
        let! content = Async.AwaitTask <| client.GetStringAsync("http://fake-response.appspot.com/?sleep=30")
        return content
    with ex ->
        // Does not catch client-side timeout exception
        return "Caught it!"
}
|> Async.RunSynchronously
// Throws System.OperationCanceledException: The operation was canceled

我可以通过使其完全同步来修复它,但更愿意保持整个堆栈异步,因为可能会并行运行其中的很多:

#r "System.Net.Http"
open System
open System.Net.Http

let client = new HttpClient()
client.Timeout <- TimeSpan.FromSeconds(1.)
try
    Async.AwaitTask <| client.GetStringAsync("http://fake-response.appspot.com/?sleep=30")
    |> Async.RunSynchronously
with ex ->
    "Caught it!"
// Returns "Caught it!"

是否有在异步上下文中捕获OperationCanceledException 的有效方法?

【问题讨论】:

  • 这似乎是 Async.Catch 打算做的事情,只是它实际上并没有捕获异常 - 行为与 OP 的示例相同。

标签: f# dotnet-httpclient f#-async


【解决方案1】:

发生这种情况是因为HttpClient.GetStringAsync 任务将被取消,而不是因为TimeoutException 而失败,因此会提示异步机制触发其无法处理的取消继续。解决这个问题的简单方法如下:

async {
    try
        let! content = 
            client.GetStringAsync("http://fake-response.appspot.com/?sleep=30")
                  .ContinueWith(fun (t:Task<string>) -> t.Result)
            |> Async.AwaitTask
        return content
    with ex ->
        // Does not catch client-side timeout exception
        return "Caught it!"
}

【讨论】:

  • 太棒了!所以,为了确保我正确理解这一点 - ContinueWith 处理任务何时被取消?而对.Result 的调用只是在任务完成之后才调用,所以它仍然是真正的异步?
  • @danielrbradley 正确。这只是强制取消作为可以由异步处理的异常来实现。
猜你喜欢
  • 2014-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多