【问题标题】:Translate Polly HTTP request to F#将 Polly HTTP 请求转换为 F#
【发布时间】:2018-07-12 23:46:16
【问题描述】:

我正在向 Polly 发出 HTTP 请求。我想在数组中的每个代理等待 1 秒后重试一次。
我怎样才能做得更好?
我怎么能在 F# 中做到这一点?

public static Result RequestWithRetry(string url, string[] proxies, string username, string password)
{
    if (proxies == null) throw new ArgumentNullException("null proxies array");
    var client = new WebClient { Credentials = new NetworkCredential(username, password) };
    var result = String.Empty;
    var proxyIndex = 0;

    var policy = Policy
            .Handle<Exception>()
            .WaitAndRetry(new[]
                {
                    TimeSpan.FromSeconds(1)
                }, (exception, timeSpan) => proxyIndex++);

    policy.Execute(() =>
    {                 
        if (proxyIndex >= proxies?.Length) throw new Exception($"Exhausted proxies: {String.Join(", ", proxies)}");

        client.Proxy = new WebProxy(proxies?[proxyIndex]) { UseDefaultCredentials = true };
        result = client.DownloadString(new Uri(url));
    });

    return new Result(value: result, proxy: proxies[proxyIndex]);
}

【问题讨论】:

    标签: c# proxy f# webclient polly


    【解决方案1】:

    您可以尝试使用Result&lt;'TOk,'TError&gt;Async&lt;T&gt; 的更多功能方式

    open System.Net
    open System
    
    type Request =
        { Url      : string
          Proxies  : string list
          UserName : string
          Password : string }
    
    let requestWithRetry request =
        let client = 
            new WebClient (
                Credentials = new NetworkCredential(
                    request.UserName,
                    request.Password))
        let uri = Uri request.Url
        let rec retry = function
            | [] -> Error "Exhausted proxies" |> async.Return
            | (proxy:string)::rest -> async {
                try 
                    do client.Proxy <- new WebProxy(proxy, UseDefaultCredentials = true)
                    let! response = client.AsyncDownloadString uri
                    return Ok (response, proxy)
                with _ ->
                    do! Async.Sleep 1000
                    return! retry rest
            }
        retry request.Proxies
    

    【讨论】:

    • 我喜欢你的回答。做得好!不幸的是,AsyncDownloadString 没有进入 .NET Core。
    • 我认为let! response = client.AsyncDownloadString uri 相当于let! response = { return client.DownloadString uri } 只有第二个适用于.NET Core。
    • @BrettRowberry,不一样。不要那样做 :D 它可能会阻塞 ThreadPool 中的每个线程而不是重用它们!您可以使用与IEvent - Async.AwaitEvent 的互操作。或者简单的Async.AwaitTask
    【解决方案2】:

    我能够把这个翻译放在一起。我不是很喜欢它,虽然在这个过程中我确实学到了更多关于 F# 和 Action 的知识。

    type Result = { Value: string; Proxy: string }
    
    let request (proxies:string[]) (username:string) (password:string) (url:string) : Result =                   
        if (proxies = null) then raise <| new ArgumentNullException()
    
        use client = new WebClient()
        client.Credentials <- NetworkCredential(username, password)
        let mutable result = String.Empty;
        let mutable proxyIndex = 0;
    
        let policy =
            Policy
                .Handle<Exception>()
                .WaitAndRetry(
                    sleepDurations = [| TimeSpan.FromSeconds(1.0) |], 
                    onRetry = Action<Exception, TimeSpan>(fun _ _ -> proxyIndex <- proxyIndex + 1)
                    )
    
        let makeCall () =
            if (proxyIndex >= proxies.Length) 
            then failwith ("Exhausted proxies: " + String.Join(", ", proxies))
            else
                let proxy = WebProxy(proxies.[proxyIndex])
                proxy.UseDefaultCredentials <- true
                client.Proxy <- proxy
                result <- client.DownloadString(new Uri(url));
    
        policy.Execute(Action makeCall)
    
        { Result.Value = result; Proxy = proxies.[proxyIndex]}
    

    【讨论】:

      猜你喜欢
      • 2017-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多