Created
January 26, 2020 23:37
-
-
Save prom3theu5/360771a12441b51e97f7bbbe240cbe30 to your computer and use it in GitHub Desktop.
Polly Resiliency for Azure Cognitive Services etc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Creates a Polly-based resiliency strategy that helps deal with transient faults when communicating | |
/// with the external (downstream) Computer Vision API service. | |
/// </summary> | |
/// <returns></returns> | |
private PolicyWrap<HttpResponseMessage> DefineAndRetrieveResiliencyStrategy() | |
{ | |
// Retry when these status codes are encountered. | |
HttpStatusCode[] httpStatusCodesWorthRetrying = { | |
HttpStatusCode.InternalServerError, // 500 | |
HttpStatusCode.BadGateway, // 502 | |
HttpStatusCode.GatewayTimeout // 504 | |
}; | |
// 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 | |
.HandleResult<HttpResponseMessage>(e => e.StatusCode == HttpStatusCode.ServiceUnavailable || | |
e.StatusCode == (System.Net.HttpStatusCode)429) | |
.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.Info($"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.Info($"Polly Circuit Breaker logging: Breaking the circuit for {breakDelay.TotalMilliseconds}ms due to: {outcome.Exception?.Message ?? outcome.Result.StatusCode.ToString()}"); | |
}, | |
onReset: () => _log.Info("Polly Circuit Breaker logging: Call ok... closed the circuit again"), | |
onHalfOpen: () => _log.Info("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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private async Task<string> MakeOCRRequest(byte[] imageBytes) | |
{ | |
_log.Info("Making OCR request"); | |
var licensePlate = string.Empty; | |
// Request parameters. | |
const string requestParameters = "language=unk&detectOrientation=true"; | |
// Get the API URL and the API key from settings. | |
// TODO 2: Populate the below two variables with the correct AppSettings properties. | |
var uriBase = ConfigurationManager.AppSettings["computerVisionApiUrl"]; | |
var apiKey = ConfigurationManager.AppSettings["computerVisionApiKey"]; | |
var resiliencyStrategy = DefineAndRetrieveResiliencyStrategy(); | |
// Configure the HttpClient request headers. | |
_client.DefaultRequestHeaders.Clear(); | |
_client.DefaultRequestHeaders.Accept.Clear(); | |
_client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); | |
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | |
// Assemble the URI for the REST API Call. | |
var uri = uriBase + "?" + requestParameters; | |
try | |
{ | |
// Execute the REST API call, implementing our resiliency strategy. | |
HttpResponseMessage response = await resiliencyStrategy.ExecuteAsync(() => _client.PostAsync(uri, GetImageHttpContent(imageBytes))); | |
// Get the JSON response. | |
var result = await response.Content.ReadAsAsync<OCRResult>(); | |
licensePlate = GetLicensePlateTextFromResult(result); | |
} | |
catch (BrokenCircuitException bce) | |
{ | |
_log.Error($"Could not contact the Computer Vision API service due to the following error: {bce.Message}"); | |
} | |
catch (Exception e) | |
{ | |
_log.Error($"Critical error: {e.Message}", e); | |
} | |
_log.Info($"Finished OCR request. Result: {licensePlate}"); | |
return licensePlate; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment