Search code examples
c#proxyf#webclientpolly

Translate Polly HTTP request to F#


I'm making an HTTP request with Polly. I would like to retry once after waiting 1 second on each proxy in an array.
How could I do this better?
How could I do this in 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]);
}

Solution

  • You may try more functional way with Result<'TOk,'TError> and Async<T>

    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