2016-05-09 2 views
6

Async.AwaitTaskHttpClientを呼び出し、エージェント(MailboxProcessor)から呼び出されています。私はHTTP呼び出し中にエラーをキャッチしたいので、非同期ワークフローでtry...withを使用しましたが、クライアント側のタイムアウト例外をキャッチしてエージェントがクラッシュする原因となります。非同期ワークフロー内でHttpClientタイムアウトを取得する

最小再現:

#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 

私はそれが完全にsyncronousすることによってそれを修正することができますが、並行して、これらの多くを実行しているかもしれないとして、スタック全体の非同期を維持することを好む:

#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を非同期コンテキスト内で捕捉する有効な方法はありますか?

+0

「Async.Catch」は、実際に例外を捕捉しないことを除いて、この動作が意図されているように見えます。動作は同じですOPの例として。 –

答えて

5

これは、TimeoutExceptionで失敗するのではなく、HttpClient.GetStringAsyncタスクがキャンセルされるために発生します。このため、非同期メカニズムは処理の継続ができないことを促します。

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!" 
} 
+0

素晴らしい!だから、これを正しく理解するために - ContinueWithは、タスクがキャンセルされたときを扱う? '.Result'への呼び出しは、タスクが完了した後でなければなりません。それで本当に非同期ですか? – danielrbradley

+2

@danielrbradley正解。これは、非同期で処理できる例外として、キャンセルを実現するだけです。 – eirik

関連する問題