F#在Async.Catch上继续

时间:2016-07-23 03:51:03

标签: f# f#-async

我正在做许多异步Web请求并使用Async.Parallel。类似的东西:

xs                          
|> Seq.map (fun u -> downloadAsync u.Url)
|> Async.Parallel
|> Async.Catch

某些请求可能会抛出异常,我想记录它们并继续使用其余的url。我找到了Async.Catch函数,但这会在抛出第一个异常时停止计算。我知道我可以在异步表达式中使用try...with表达式来计算整个列表,但是,我认为这意味着将日志函数传递给我的downloadAsync函数改变他的类型。有没有其他方法来捕获异常,记录它们并继续其余的网址?

1 个答案:

答案 0 :(得分:4)

'''是将捕获移动到地图中,以便捕获并行化:

open System
open System.IO
open System.Net

type T = { Url : string }

let xs = [
    { Url = "http://microsoft.com" }
    { Url = "thisDoesNotExists" } // throws when constructing Uri, before downloading
    { Url = "https://thisDotNotExist.Either" }
    { Url = "http://google.com" }
]

let isAllowedInFileName c =
    not <| Seq.contains c (Path.GetInvalidFileNameChars())

let downloadAsync url =
    async {
        use client = new WebClient()
        let fn =
            [|
                __SOURCE_DIRECTORY__
                url |> Seq.filter isAllowedInFileName |> String.Concat
            |]
            |> Path.Combine
        printfn "Downloading %s to %s" url fn
        return! client.AsyncDownloadFile(Uri(url), fn)
    }

xs
|> Seq.map (fun u -> downloadAsync u.Url |> Async.Catch)
|> Async.Parallel
|> Async.RunSynchronously
|> Seq.iter (function
    | Choice1Of2 () -> printfn "Succeeded"
    | Choice2Of2 exn -> printfn "Failed with %s" exn.Message)

(*
Downloading http://microsoft.com to httpmicrosoft.com
Downloading thisDoesNotExists to thisDoesNotExists
Downloading http://google.com to httpgoogle.com
Downloading https://thisDotNotExist.Either to httpsthisDotNotExist.Either
Succeeded
Failed with Invalid URI: The format of the URI could not be determined.
Failed with The remote name could not be resolved: 'thisdotnotexist.either'
Succeeded
*)

在这里,我将下载内容包装到另一个async中,以捕获Uri构造异常。