8

Tôi đang cố thực hiện yêu cầu web không đồng bộ cho URL sẽ trả về nếu yêu cầu mất quá nhiều thời gian. Tôi đang sử dụng F # không đồng bộ công việc và thư viện System.Net.Http để làm điều này.tính toán không đồng bộ không bắt được OperationCancelledException

Tuy nhiên, tôi không thể nắm bắt được Task/OperationCancelledExceptions được tăng lên bởi thư viện System.Net.Http trong luồng công việc async. Thay vào đó, các ngoại lệ xảy ra ở phương pháp Async.RunSynchronously, như bạn có thể thấy trong stack trace này:

> 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>[email protected]() 

Mã:

#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 
+0

Nói chung, trường hợp ngoại lệ là vui nhộn với async. Bạn muốn sử dụng 'Async.Catch'. Các hành vi lạ được gây ra khi ngoại lệ được rethrown trên thread chính gây ra các dấu vết stack lẻ. –

+0

Tôi đã thử viết điều này theo kiểu Async.Catch và sự cố vẫn xảy ra. Một điều nữa là nếu một loại ngoại lệ khác được ném ra, nó sẽ bị bắt chính xác. Tôi tự hỏi nếu mô-đun Async xử lý các mã thông báo hủy có thể có lỗi - có lẽ nó giải thích sai về ngoại lệ như một yêu cầu hủy bỏ đối với mô-đun. – WiseGuyEh

Trả lời

6

hủy luôn khác nhau từ lỗi. Trong trường hợp của bạn, bạn có thể thay đổi hành vi mặc định của AwaitTask mà gọi "hủy tiếp tục" nếu nhiệm vụ bị hủy và xử lý theo cách khác:

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 
} 
Các vấn đề liên quan