在异步工作流中捕获 HttpClient 超时
Catching HttpClient timeouts within an async workflow
我正在通过 Async.AwaitTask
呼叫 HttpClient
,是从代理 (MailboxProcessor) 中呼叫的。我想在 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
的有效方法?
发生这种情况是因为 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!"
}
我正在通过 Async.AwaitTask
呼叫 HttpClient
,是从代理 (MailboxProcessor) 中呼叫的。我想在 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
的有效方法?
发生这种情况是因为 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!"
}