title: Using Polly to retry on different Urls after failing retries
body: <p>I'm working on a proof of concept in .Net Core and new to polly and struggling to understand how to do configure it in such a way as to define a retry policy but after this fails we switch to a different url and retry on this (there may be a number of these and the list of available Urls is dynamic) </p>
  
  <p>My preference is to use the HttpClientFactory and Typed Clients as described here
  <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1#typed-clients" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1#typed-clients</a></p>
  
  <p>I've looked at 
  <a href="https://github.com/App-vNext/Polly/issues/199" rel="nofollow noreferrer">https://github.com/App-vNext/Polly/issues/199</a></p>
  
  <p><a href="https://github.com/App-vNext/Polly/issues/591" rel="nofollow noreferrer">https://github.com/App-vNext/Polly/issues/591</a></p>
  
  <p>But cannot how to see how to apply these to a dynamic list and within the HttpClientFactory/ Typed Client approach</p>
  
  <pre><code>// Attempting to enable dynamic clients
  // https://github.com/App-vNext/Polly/issues/199
  // https://github.com/App-vNext/Polly/issues/591 using HttpClientfactory
  
  
   services.AddHttpClient&lt;IAppointmentServiceClient, AppointmentServiceClient&gt;()
                  .ConfigureHttpClient((serviceProvider, client) =&gt;
  {
                      var serverList = ServiceRegistration.LocateServiceList("AppointmentService").Result;
                      var random = new Random();
                      int index = random.Next(serverList.Count);
                      var baseAddress = new Uri($"http://{ serverList[index]}");
  
  
                      client.BaseAddress = baseAddress;
                  })
                  .AddPolicyHandler(GetRetryPolicy())
  
                  //.AddPolicyHandler(GetCircuitBreakerPolicy());
                  .AddPolicyHandler((sp, req, key) =&gt;
                  {
                      return GetCircuitBreakerPolicy();
                  },
                  GetPolicyKey
                  );
  }
  
  
  static string GetPolicyKey(HttpRequestMessage httpRequestMessage)
  {
   return httpRequestMessage.RequestUri.Authority;
  }
  
  
  static IAsyncPolicy&lt;HttpResponseMessage&gt; GetRetryPolicy()
  {
         return HttpPolicyExtensions
                .HandleTransientHttpError()
                .OrResult(msg =&gt; msg.StatusCode == System.Net.HttpStatusCode.NotFound)
                .WaitAndRetryAsync(3, retryAttempt =&gt; TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                  onRetryAsync: async (outcome, timespan, retryCount, context) =&gt; {
                      context["RetriesInvoked"] = retryCount; // allows us to capture the reties downstream, potential for extra logging 
  
                  });
  
  }
  
  static IAsyncPolicy&lt;HttpResponseMessage&gt; GetCircuitBreakerPolicy()
          {
              return HttpPolicyExtensions
                  .HandleTransientHttpError()
                  .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30), 
                      onBreak: (ex, breakDelay, context) =&gt;
                      {
  
                      },
                      onReset: (context)=&gt; 
                      {
  
                      },
                      onHalfOpen: () =&gt; { }
                  );
  }
  
  </code></pre>
  
  <p>The actual call is just </p>
  
  <pre><code>public AppointmentServiceClient(HttpClient httpClient)
  {
      _apiClient = httpClient;
  }
  
  public async Task&lt;IEnumerable&lt;AppointmentEntity&gt;&gt; GetResourceAppointments(string resourceId, DateTimeOffset date)
          {
  
              var url = GetResourceAppointmentsUrl(resourceId, date);
  
              var context = new Polly.Context();
              //context["baseUrls"] = _serverList;
  
              HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
              request.SetPolicyExecutionContext(context);
              var response = await _apiClient.SendAsync(request);
  
              context = response.RequestMessage?.GetPolicyExecutionContext(); // (if not already held in a local variable)
              //if (context?.TryGetValue("RetriesInvoked", out int? retriesNeeded) ?? false)
              //{
              //    // Do something with int? retriesNeeded
              //}
  
  
              response.EnsureSuccessStatusCode();
              var appointmentResponse = await response.Content.ReadAsStringAsync();
  
              return JsonConvert.DeserializeObject&lt;IEnumerable&lt;AppointmentEntity&gt;&gt;(appointmentResponse);
          }
  
  </code></pre>