in Hands-on lab/lab-files/src/TollBooth/TollBooth/FindLicensePlateText.cs [186:235]
private AsyncPolicyWrap<HttpResponseMessage> DefineAndRetrieveResiliencyStrategy()
{
// Retry when these status codes are encountered.
HttpStatusCode[] httpStatusCodesWorthRetrying = {
HttpStatusCode.InternalServerError, // 500
HttpStatusCode.BadGateway, // 502
HttpStatusCode.GatewayTimeout // 504
};
// Immediately fail (fail fast) when these status codes are encountered.
HttpStatusCode[] httpStatusCodesToImmediatelyFail = {
HttpStatusCode.BadRequest, // 400
HttpStatusCode.Unauthorized, // 401
HttpStatusCode.Forbidden // 403
};
// Define our waitAndRetry policy: retry n times with an exponential backoff in case the Computer Vision API throttles us for too many requests.
var waitAndRetryPolicy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(e => e.StatusCode == HttpStatusCode.ServiceUnavailable ||
e.StatusCode == (System.Net.HttpStatusCode)429 || e.StatusCode == (System.Net.HttpStatusCode)403)
.WaitAndRetryAsync(10, // Retry 10 times with a delay between retries before ultimately giving up
attempt => TimeSpan.FromSeconds(0.25 * Math.Pow(2, attempt)), // Back off! 2, 4, 8, 16 etc times 1/4-second
//attempt => TimeSpan.FromSeconds(6), // Wait 6 seconds between retries
(exception, calculatedWaitDuration) =>
{
_log.LogWarning($"Computer Vision API server is throttling our requests. Automatically delaying for {calculatedWaitDuration.TotalMilliseconds}ms");
}
);
// Define our first CircuitBreaker policy: Break if the action fails 4 times in a row.
// This is designed to handle Exceptions from the Computer Vision API, as well as
// a number of recoverable status messages, such as 500, 502, and 504.
var circuitBreakerPolicyForRecoverable = Policy
.Handle<HttpResponseException>()
.OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(3),
onBreak: (outcome, breakDelay) =>
{
_log.LogWarning($"Polly Circuit Breaker logging: Breaking the circuit for {breakDelay.TotalMilliseconds}ms due to: {outcome.Exception?.Message ?? outcome.Result.StatusCode.ToString()}");
},
onReset: () => _log.LogInformation("Polly Circuit Breaker logging: Call ok... closed the circuit again"),
onHalfOpen: () => _log.LogInformation("Polly Circuit Breaker logging: Half-open: Next call is a trial")
);
// Combine the waitAndRetryPolicy and circuit breaker policy into a PolicyWrap. This defines our resiliency strategy.
return Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicyForRecoverable);
}