public PollySqlConnection(string connectionString, IAsyncPolicy[] asyncPolicies, ISyncPolicy[] syncPolicies) { _connectionString = connectionString; _asyncPolicies = asyncPolicies; _syncPolicies = syncPolicies; if (asyncPolicies == null) { throw new ArgumentNullException($"{nameof(asyncPolicies)} must have at least one async policy provided"); } if (asyncPolicies.Length == 1) { _singleAsyncPolicy = asyncPolicies[0]; } else { _asyncPolicyWrapper = Policy.WrapAsync(asyncPolicies); } if (syncPolicies == null) { throw new ArgumentNullException($"{nameof(syncPolicies)} must have at least one sync policy provided"); } if (syncPolicies.Length == 1) { _singleSyncPolicy = syncPolicies[0]; } else { _syncPolicyWrapper = Policy.Wrap(syncPolicies); } _connection = new SqlConnection(connectionString); }
private async Task <FaceDetectResult[]> MakeFaceIdentifyRequest(FaceIdentifyRequest req, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { string strResult = string.Empty; StringBuilder faceids = new StringBuilder(); req.FaceIds.ToList().ForEach(s => faceids.Append(s + " ")); _log.Info($"Making identify request faceids: {faceids} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); FaceDetectResult[] result = null; // Get the API URL and the API key from settings. var uri = ConfigurationManager.AppSettings["faceIdentifyApiUrl"]; // 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")); try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetIdentifyHttpContent(req))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"identify completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceIdentifyRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
/// <summary> /// Register instance in DI. /// </summary> /// <typeparam name="TClient">Interface implemented by a type.</typeparam> /// <typeparam name="TImplementation">A type implements TClient interface.</typeparam> /// <param name="services">instance of IServiceCollection.</param> /// <param name="policy">circuit breaker policy.</param> public static void RegisterInstace <TClient, TImplementation>(this IServiceCollection services, PolicyWrap <HttpResponseMessage> policy) where TClient : class where TImplementation : class, TClient { PolicyBuilder policyBuilder = new PolicyBuilder(); services.AddHttpClient <TClient, TImplementation>() .AddPolicyHandler(t => { return(policy); }) .CorrelateRequests("X-Correlation-ID") .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip }); }
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToTimeout = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(AsyncDemo09_Wrap_Fallback_Timeout_WaitAndRetry).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); Stopwatch watch = null; // Define our timeout policy: time out after 2 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it. var timeoutPolicy = Policy .TimeoutAsync(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic); // Define our waitAndRetry policy: keep retrying with 4 second gaps. This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry. var waitAndRetryPolicy = Policy .Handle <Exception>() // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define a fallback policy: provide a nice substitute message to the user, if we found the call was rejected due to the timeout policy. FallbackPolicy <String> fallbackForTimeout = Policy <String> .Handle <TimeoutRejectedException>() .FallbackAsync( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallbackAsync: async b => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToTimeout++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); /* do something else async if desired */ return("Please try again later [Fallback for any exception]"); }, onFallbackAsync: async e => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForTimeout).WrapAsync(timeoutPolicy).WrapAsync(waitAndRetryPolicy); using (var client = new HttpClient()) { totalRequests = 0; bool internalCancel = false; while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap string response = await policyWrap.ExecuteAsync(ct => client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); progress.Report(ProgressWithMessage("Response: " + response + "(after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public static async Task ExecuteAsync(CancellationToken cancellationToken) { Console.WriteLine(typeof(AsyncDemo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name); Console.WriteLine("======="); // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. var client = new HttpClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToCircuitBreaking = 0; int eventualFailuresForOtherReasons = 0; // Define our waitAndRetry policy: keep retrying with 200ms gaps. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { // This is your new exception handler! // Tell the user what they've won! ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { ConsoleHelper.WriteLineInColor(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ConsoleColor.Magenta); ConsoleHelper.WriteLineInColor("..due to: " + ex.Message, ConsoleColor.Magenta); }, onReset: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta), onHalfOpen: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta) ); // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap. PolicyWrap policyWrap = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable && !cancellationToken.IsCancellationRequested) { i++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string msg = await policyWrap.ExecuteAsync <String>(ct => { // This code is executed through both policies in the wrap: WaitAndRetry outer, then CircuitBreaker inner. Demo 06 shows a broken-out version of what this is equivalent to. return(client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + i)); }, cancellationToken); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteInColor("Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); ConsoleHelper.WriteInColor("Request " + i + " failed with: " + b.GetType().Name, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); ConsoleHelper.WriteInColor("Request " + i + " eventually failed with: " + e.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); } Console.WriteLine(""); Console.WriteLine("Total requests made : " + i); Console.WriteLine("Requests which eventually succeeded : " + eventualSuccesses); Console.WriteLine("Retries made to help achieve success : " + retries); Console.WriteLine("Requests failed early by broken circuit : " + eventualFailuresDueToCircuitBreaking); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }
public RpdClient(RpdNetworkConfig config) { this.config = config; this.client = new RestClient(config.BaseUrl); this.policy = RestPolicy.DefaultPolicy(config.RetryAttempts, config.TimeOut); }
public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log) { Guid requestID = Guid.NewGuid(); try { log.Info($"LoadPersonGroup was triggered request id {requestID}"); string largepersongroupid = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "groupid", true) == 0) .Value; if (largepersongroupid == null) { // Get request body dynamic data = await req.Content.ReadAsAsync <object>(); largepersongroupid = data?.groupid; } if (largepersongroupid != null) { string apis = ConfigurationManager.AppSettings["apis"]; string[] apiArr = apis.Split(','); if (apiArr.Length > 0) { _loadPersonClient = _loadPersonClient ?? new HttpClient(); PolicyWrap <HttpResponseMessage> resilientPolicy = FaceHelper.DefineAndRetrieveResiliencyStrategy(log); int i; //setting the map of api to database in database 1 IDatabase cache = Connection.GetDatabase(1); for (i = 1; i <= apiArr.Length; i++) { cache.StringSet(apiArr[i - 1], i + 1); } var personResult = new ListPersonGroup(log, _loadPersonClient); for (i = 1; i <= apiArr.Length; i++) { bool isComplete = false; string lastPerson = string.Empty; Task <InternalPersonDetails[]> task; List <InternalPersonDetails> personList = new List <InternalPersonDetails>(); cache = Connection.GetDatabase(i + 1); while (!isComplete) { task = personResult.GetListPersonGroup(lastPerson, apiArr[i - 1], largepersongroupid, requestID, resilientPolicy); task.Wait(); if (task.Result.Length < 1000) { isComplete = true; } if (task.Result.Length > 0) { lastPerson = task.Result[task.Result.Length - 1].PersonId.ToString(); personList.AddRange(task.Result.ToList()); } int loop = task.Result.Length / 100; var tmplist = task.Result.ToList(); int k = 0, len = 0; for (k = 0; k < loop; k++) { var tmpinnerlist = tmplist.GetRange(k * 100, 100); len += tmpinnerlist.Count; cache.StringSet(tmpinnerlist.Select(s => new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always); } if (tmplist.Count - len > 0) { var tmpinnerlist = tmplist.GetRange(k * 100, tmplist.Count - len); cache.StringSet(tmpinnerlist.Select(s => new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always); } } } return(req.CreateResponse(HttpStatusCode.OK, "Redis loaded successfully")); } else { string msg = "List of Api setting is empty"; log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}"); return(req.CreateResponse(HttpStatusCode.BadRequest, "List of Api setting is empty")); } } else { string msg = "Please pass a large person group id on the query string or in the request body"; log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}"); return(req.CreateResponse(HttpStatusCode.BadRequest, msg)); } } catch (Exception e) { log.Error($"Exception-LoadPersonGroup: {e.Message} requestId: {requestID} ticks: {DateTime.Now.Ticks}", e); return(req.CreateResponse(HttpStatusCode.BadRequest, e.Message)); } }
public async Task <InternalPersonDetails[]> GetListPersonGroup(string startPerson, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { return(await MakeListPersonGroupRequest(startPerson, apiKey, largegroupid, requestId, policy)); }
public static List <TestUser> GetUsers() { //Retry untill other side return users successfull, //After 3 tries, just return John Doe... //Fallback policy -> create John Doe PolicyWrap <List <TestUser> > policy = CreateWaitPolicy(); var users = GetTimeRegistrationDemoUsers(); users.Wait(50000); var testUsers = users.Result.Users.Select(x => new TestUser { SubjectId = x.Id.ToString(), Username = x.FirstName, Password = x.LastName, Claims = new List <Claim> { new Claim("name", x.FirstName + " " + x.LastName), new Claim("role", x.Roles.FirstOrDefault().Id) } } ).ToList(); return(testUsers); //return new List<TestUser> //{ // new TestUser // { // SubjectId = "50", // Username = "******", // Password = "******", // Claims = new List<Claim> // { // new Claim("name", "jef"), // new Claim("role","Employee") // } // }, // new TestUser // { // SubjectId = "1", // Username = "******", // Password = "******", // Claims = new List<Claim> // { // new Claim("name", "alice"), // new Claim("website", "https://alice.com"), // new Claim("role","Administrators") // } // }, // new TestUser // { // SubjectId = "2", // Username = "******", // Password = "******", // Claims = new List<Claim> // { // new Claim("name", "bob"), // new Claim("website", "https://bob.com"), // new Claim("role","Managers") // } // } //}; }
public void AddPolicy(string origin, PolicyWrap policy) { }
public T Execute<T>(Func<T> operation, Func<T> openStateOperation) { // Define our waitAndRetry policy: keep retrying with n ms gaps. RetryPolicy waitAndRetryPolicy = Policy .Handle<Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForever( attempt => TimeSpan.FromMilliseconds(SiteSettings.Instance.SleepDurationsMilliseconds), (exception, calculatedWaitDuration) => { _log.Error(".Log, then retry: ", exception); }); // Define our CircuitBreaker policy: Break if the action fails n times in a row. CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle<Exception>() .CircuitBreaker( exceptionsAllowedBeforeBreaking: SiteSettings.Instance.ExceptionsAllowedBeforeBreaking, durationOfBreak: TimeSpan.FromSeconds(1), onBreak: (ex, breakDelay) => { _log.Error($".Breaker logging: Breaking the circuit for {breakDelay.TotalMilliseconds} + ms!"); _log.Error($"..due to: {ex.Message}"); }, onReset: () => { _log.Error(".Breaker logging: Call ok! Closed the circuit again!"); }, onHalfOpen: () => { _log.Error(".Breaker logging: Half-open: Next call is a trial!"); } ); // Define a fallback policy: provide a secondary services or substitute result to the user, for any exception. FallbackPolicy<T> fallbackForAnyException = Policy<T> .Handle<Exception>() .Fallback( fallbackAction: openStateOperation, onFallback: e => { _log.Error($"Fallback catches eventually failed with: {e.Exception.Message}"); } ); // We combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); // We wrap the two fallback policies onto the front of the existing wrap too. And the fact that the PolicyWrap myResilienceStrategy from above is just another Policy, which can be onward-wrapped too. // With this pattern, you can build an overall resilience strategy programmatically, reusing some common parts (eg PolicyWrap myResilienceStrategy) but varying other parts (eg Fallback) individually for different calls. PolicyWrap<T> policyWrap = fallbackForAnyException.Wrap(myResilienceStrategy); try { // Manage the call according to the whole policy wrap. var response = policyWrap.Execute(operation); return response; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { _log.Error("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); return default(T); } }
public override void Execute(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToTimeout = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(Demo09_Wrap_Fallback_Timeout_WaitAndRetry).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); Stopwatch watch = null; // Define our timeout policy: time out after 2 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it. var timeoutPolicy = Policy .Timeout(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic, // This use of onTimeout demonstrates the point about capturing walked-away-from Tasks with TimeoutStrategy.Pessimistic discussed in the Polly wiki, here: https://github.com/App-vNext/Polly/wiki/Timeout#pessimistic-timeout-1 onTimeout: (ctx, span, abandonedTask) => { { abandonedTask.ContinueWith(t => { // ContinueWith important!: the abandoned task may very well still be executing, when the caller times out on waiting for it! if (t.IsFaulted) { progress.Report(ProgressWithMessage(".The task previously walked-away-from now terminated with exception: " + t.Exception.Message, Color.Yellow)); } else if (t.IsCanceled) { // (If the executed delegates do not honour cancellation, this IsCanceled branch may never be hit. It can be good practice however to include, in case a Policy configured with TimeoutStrategy.Pessimistic is used to execute a delegate honouring cancellation.) progress.Report(ProgressWithMessage(".The task previously walked-away-from now was canceled.", Color.Yellow)); } else { // extra logic (if desired) for tasks which complete, despite the caller having 'walked away' earlier due to timeout. progress.Report(ProgressWithMessage(".The task previously walked-away-from now eventually completed.", Color.Yellow)); } }); } } ); // Define our waitAndRetry policy: keep retrying with 4 second gaps. This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define a fallback policy: provide a nice substitute message to the user, if we found the call was rejected due to the timeout policy. FallbackPolicy <String> fallbackForTimeout = Policy <String> .Handle <TimeoutRejectedException>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallback: b => { watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToTimeout++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <String> policyWrap = fallbackForAnyException.Wrap(fallbackForTimeout).Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy); using (var client = new WebClient()) { bool internalCancel = false; totalRequests = 0; while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string response = policyWrap.Execute(ct => client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); progress.Report(ProgressWithMessage("Response: " + response + "(after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second Thread.Sleep(500); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
private async Task <FaceDetectResult[]> MakeFaceDetectRequest(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { _log.Info($"Making detect request requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); string strResult = string.Empty; FaceDetectResult[] result = null; // Request parameters. const string requestParameters = "returnFaceId=true&returnFaceLandmarks=false"; // Get the API URL and the API key from settings. var uriBase = ConfigurationManager.AppSettings["faceDetectApiUrl"]; // 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 policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetImageHttpContent(imageBytes))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"detect completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceDetectRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
public async Task <FaceDetectResult[]> DetectFaces(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { return(await MakeFaceDetectRequest(imageBytes, apiKey, requestId, policy)); }
public CustomersAPIService(HttpClient client, Policy[] resiliencePolicies) { _client = client; _policy = Policy.WrapAsync(resiliencePolicies); }
public static IRestResponse ExecuteWithPolicy(this IRestClient client, IRestRequest request, PolicyWrap policy) { // capture the exception so we can push it though the standard response flow. PolicyResult <IRestResponse> val = policy.ExecuteAndCapture(() => client.Execute(request)); IRestResponse restResponse = val.Result; if (restResponse == null) { restResponse = new RestResponse { Request = request, ErrorException = val.FinalException }; } return(restResponse); }
static void Main(string[] args) { Console.WriteLine("Hello World!"); Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("log-.txt", rollingInterval: RollingInterval.Day) .CreateLogger(); _circuitBreakerPolicy = Policy.Handle <HttpRequestException>() .CircuitBreaker( // number of exceptions before breaking circuit 5, // time circuit opened before retry TimeSpan.FromMinutes(1), (exception, duration) => { // on circuit opened Log.Information("Circuit breaker opened"); }, () => { // on circuit closed Log.Information("Circuit breaker reset"); }); _retryPolicy = Policy.Handle <HttpRequestException>() .WaitAndRetry( // number of retries 4, // exponential backofff retryAttempt => TimeSpan.FromSeconds(retryAttempt), // on retry (exception, timeSpan, retryCount, context) => { var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " + $"of {context.PolicyKey} " + $"at {context.ExecutionKey}"; Log.Warning(msg); }); // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken. FallbackPolicy <UserPayload> fallbackForCircuitBreaker = Policy <UserPayload> .Handle <BrokenCircuitException>() .Fallback( fallbackValue: new UserPayload { Users = null, ErrorMessage = "Please try again later [Fallback for broken circuit]" }, onFallback: b => { Log.Information("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <UserPayload> fallbackForAnyException = Policy <UserPayload> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return(new UserPayload { Users = null, ErrorMessage = "Please try again later [Fallback for any exception]" }); }, onFallback: e => { Log.Information("Fallback catches failed with: " + e.Exception.Message, ConsoleColor.DarkMagenta); } ); PolicyWrap myResilienceStrategy = Policy.Wrap(_retryPolicy, _circuitBreakerPolicy); PolicyWrap <UserPayload> policyWrap = fallbackForAnyException.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy)); LoopCalls(policyWrap); }
public ResilientHttpClient(ILogger logger) { this.logger = logger; policyWrapper = Policy.WrapAsync(CreatePolicies()); }
private async Task <InternalPersonDetails[]> MakeListPersonGroupRequest(string startPerson, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { string strResult = string.Empty; _log.Info($"Making ListPerson GET request requestId: {requestId} apiKey:{apiKey} start person {startPerson} ticks: {DateTime.Now.Ticks}"); InternalPersonDetails[] result = null; // Request parameters. string requestParameters = largegroupid + "/persons"; // Get the API URL and the API key from settings. var uriBase = ConfigurationManager.AppSettings["facePersonApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); // Assemble the URI for the REST API Call. var uri = uriBase + "/" + requestParameters; if (startPerson != string.Empty) { uri += "?start=" + startPerson; } try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.GetAsync(uri)); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <InternalPersonDetails[]>(); _log.Info($"ListPersonGroup completed: requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeListPersonGroupRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
public ResilientHttpClient(Policy[] policies, ILogger logger) { this.logger = logger; // Add Policies to be applied policyWrapper = Policy.WrapAsync(policies); }
public static async Task <bool> RunDetect(Guid requestID, string apis, string name, string source, Stream incomingPicture, string sourceContainerName, string resultContainerName, IAsyncCollector <object> outputItem, TraceWriter log, string videoName = null) { string apikey = string.Empty; try { string[] apiArr = apis.Split(','); int randomApi = FaceHelper.Instance.Next(0, apiArr.Length); apikey = apiArr[randomApi]; log.Info($"RunDetect request id: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); Tuple <HttpClient, PolicyWrap <HttpResponseMessage> > tuple = FaceHelper.HttpClientList.GetOrAdd(apikey, new Tuple <HttpClient, PolicyWrap <HttpResponseMessage> >( new HttpClient(), FaceHelper.DefineAndRetrieveResiliencyStrategy(log))); HttpClient client = tuple.Item1; PolicyWrap <HttpResponseMessage> policy = tuple.Item2; IDatabase cache = FaceHelper.Connection.GetDatabase(int.Parse(FaceHelper.Connection.GetDatabase(1).StringGet(apikey))); //the large group id it's based on the mac address we get - each MAC address can work with different face api group string largegroupid = ConfigurationManager.AppSettings[source]; if (videoName == null) { log.Info($"Detecting {name} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); } else { log.Info($"Detecting thumbnail {name} from {videoName} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); } byte[] pictureImage; // Convert the incoming image stream to a byte array. using (var br = new BinaryReader(incomingPicture)) { pictureImage = br.ReadBytes((int)incomingPicture.Length); } var detectionResult = await new FaceDetect(log, client).DetectFaces(pictureImage, apikey, requestID, policy); if ((detectionResult != null) && (detectionResult.Length > 0)) { //prepare identify request int maxCandidate = int.Parse(ConfigurationManager.AppSettings["maxNumOfCandidatesReturned"]); double threshold = double.Parse(ConfigurationManager.AppSettings["confidenceThreshold"]); var identifyResquest = new FaceIdentifyRequest() { ConfidenceThreshold = threshold, MaxNumOfCandidatesReturned = maxCandidate, LargePersonGroupId = largegroupid, FaceIds = detectionResult.Select(s => s.FaceId).ToArray() }; var identifyResult = await new FaceIdentify(log, client).IdentifyFaces(identifyResquest, apikey, requestID, policy); if ((identifyResult == null) || (identifyResult.Length == 0)) { log.Info($"No identification result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}"); } var personResult = new PersonDetails(log, client); //merging results and find person name for (int i = 0; i < detectionResult.Length; i++) { if (videoName == null) { detectionResult[i].FaceBlobName = string.Concat(detectionResult[i].FaceId, "_", name); } else { detectionResult[i].FaceBlobName = videoName + "/" + name; } if ((identifyResult != null) && (identifyResult.Length > 0)) { detectionResult[i].Candidates = identifyResult[i].Candidates; for (int j = 0; j < detectionResult[i].Candidates.Length; j++) { string personid = detectionResult[i].Candidates[j].PersonId.ToString(); string personName = cache.StringGet(largegroupid + "-" + personid); if (string.IsNullOrEmpty(personName) == true) { log.Info($"Missing cache requestId: {requestID} apiKey: {apikey} personId: {personid} ticks: {DateTime.Now.Ticks}"); var tPerson = await personResult.GetPersonName(personid, apikey, largegroupid, requestID, policy); personName = tPerson.Name; cache.StringSet(largegroupid + "-" + personid, personName, null, When.Always); } detectionResult[i].Candidates[j].PersonName = new InternalPersonDetails() { PersonId = detectionResult[i].Candidates[j].PersonId, Name = personName }; } } } } else { log.Info($"No dectection result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}"); //in case of video, we want to create a link to the face detected by AMS (Azure Media Services) although face api didn't recognize it if (videoName != null) { detectionResult = new FaceDetectResult[1] { new FaceDetectResult() { FaceBlobName = videoName + "/" + name } } } ; } string blobname = videoName ?? name; var actionResult = new FaceIdentifyResult() { BlobName = blobname, ContainerName = sourceContainerName, ResultContainerName = resultContainerName, BlobLength = incomingPicture.Length, CreatedDateTime = DateTime.UtcNow, RequestId = requestID, ApiKey = apikey, LargeGroupId = largegroupid, Source = source, DetectResultList = detectionResult }; string strResult = JsonConvert.SerializeObject(actionResult); await outputItem.AddAsync(strResult); } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}", ex); return(false); } return(true); }
public PollyServiceClient() { _client = new HttpClient(); _gatewayUri = _primaryUri; var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { //Called when circuit first open //Setting the backupUri so calls now go to backup gateway _gatewayUri = _backupUri; }, onReset: () => { //Called when circuit is closed again. //Primary gateway is responding again, setting to primaryUri. _gatewayUri = _primaryUri; }, onHalfOpen: () => { //Called when the policy is going to check the original call to see if there are no exceptions. //Send the call to the primary gateway to see if it's operational again. _gatewayUri = _primaryUri;; } ); var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { //Handle the exception here. }); FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String> .Handle <BrokenCircuitException>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); //This is called after the circuit breaker is tripped //and the gatewayUri is changed to point to the backup //gateway. This call runs on the backup gateway. return(await ClientWrapper()); }, onFallbackAsync: async e => { await Task.FromResult(true); } ); //Something really bad has happened. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); return("Another exception occurred."); }, onFallbackAsync: async e => { await Task.FromResult(true); } ); PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); _policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy)); }
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToCircuitBreaking = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(AsyncDemo08_Wrap_Fallback_WaitAndRetry_CircuitBreaker).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); Stopwatch watch = null; // Define our waitAndRetry policy: keep retrying with 200ms gaps. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { progress.Report(ProgressWithMessage(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta)); progress.Report(ProgressWithMessage("..due to: " + ex.Message, Color.Magenta)); }, onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Call ok! Closed the circuit again!", Color.Magenta)), onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: Next call is a trial!", Color.Magenta)) ); // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken. FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String> .Handle <BrokenCircuitException>() .FallbackAsync( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [message substituted by fallback policy]", onFallbackAsync: async b => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches failed with: " + b.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToCircuitBreaking++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .FallbackAsync( fallbackAction: /* Demonstrates fallback action/func syntax */ async ct => { await Task.FromResult(true); /* do something else async if desired */ return("Please try again later [Fallback for any exception]"); }, onFallbackAsync: async e => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback catches eventually failed with: " + e.Exception.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // As demo07: we combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); // Added in demo08: we wrap the two fallback policies onto the front of the existing wrap too. Demonstrates the *instance* wrap syntax. And the fact that the PolicyWrap myResilienceStrategy from above is just another Policy, which can be onward-wrapped too. // With this pattern, you can build an overall resilience strategy programmatically, reusing some common parts (eg PolicyWrap myResilienceStrategy) but varying other parts (eg Fallback) individually for different calls. PolicyWrap <String> policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy)); // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.WrapAsync(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); totalRequests = 0; using (var client = new HttpClient()) { bool internalCancel = false; // Do the following until a key is pressed while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap string response = await policyWrap.ExecuteAsync(ct => client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); // Display the response message on the console progress.Report(ProgressWithMessage("Response : " + response + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
/// <summary> /// Initializes a new instance of the <see cref="T:EasyCaching.HybridCache.HybridCachingProvider"/> class. /// </summary> /// <param name="name">Name.</param> /// <param name="optionsAccs">Options accs.</param> /// <param name="factory">Providers factory</param> /// <param name="bus">Bus.</param> /// <param name="loggerFactory">Logger factory.</param> public HybridCachingProvider( string name , HybridCachingOptions optionsAccs , IEasyCachingProviderFactory factory , IEasyCachingBus bus = null , ILoggerFactory loggerFactory = null ) { ArgumentCheck.NotNull(factory, nameof(factory)); this._name = name; this._options = optionsAccs; ArgumentCheck.NotNullOrWhiteSpace(_options.TopicName, nameof(_options.TopicName)); this._logger = loggerFactory?.CreateLogger <HybridCachingProvider>(); // Here use the order to distinguish traditional provider var local = factory.GetCachingProvider(_options.LocalCacheProviderName); if (local.IsDistributedCache) { throw new NotFoundCachingProviderException("Can not found any local caching providers."); } else { this._localCache = local; } // Here use the order to distinguish traditional provider var distributed = factory.GetCachingProvider(_options.DistributedCacheProviderName); if (!distributed.IsDistributedCache) { throw new NotFoundCachingProviderException("Can not found any distributed caching providers."); } else { this._distributedCache = distributed; } this._bus = bus ?? NullEasyCachingBus.Instance; this._bus.Subscribe(_options.TopicName, OnMessage); this._cacheId = Guid.NewGuid().ToString("N"); // policy retryAsyncPolicy = Policy.Handle <Exception>() .WaitAndRetryAsync(this._options.BusRetryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt - 1))); retryPolicy = Policy.Handle <Exception>() .WaitAndRetry(this._options.BusRetryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt - 1))); fallbackPolicy = Policy.Handle <Exception>().Fallback(() => { }); fallbackAsyncPolicy = Policy.Handle <Exception>().FallbackAsync(ct => { return(Task.CompletedTask); }); _busSyncWrap = Policy.Wrap(fallbackPolicy, retryPolicy); _busAsyncWrap = Policy.WrapAsync(fallbackAsyncPolicy, retryAsyncPolicy); }
public static void Execute() { Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); Console.WriteLine("======="); // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. var client = new WebClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToCircuitBreaking = 0; int eventualFailuresForOtherReasons = 0; Stopwatch watch = null; // Define our waitAndRetry policy: keep retrying with 200ms gaps. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForever( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreaker( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { ConsoleHelper.WriteLineInColor(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ConsoleColor.Magenta); ConsoleHelper.WriteLineInColor("..due to: " + ex.Message, ConsoleColor.Magenta); }, onReset: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta), onHalfOpen: () => ConsoleHelper.WriteLineInColor(".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta) ); // Define a fallback policy: provide a nice substitute message to the user, if we found the circuit was broken. FallbackPolicy <String> fallbackForCircuitBreaker = Policy <String> .Handle <BrokenCircuitException>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for broken circuit]", onFallback: b => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches eventually failed with: " + e.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } ); // As demo07: we combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap, using the *static* Policy.Wrap syntax. PolicyWrap myResilienceStrategy = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); // Added in demo08: we wrap the two fallback policies onto the front of the existing wrap too. Demonstrates the *instance* wrap syntax. And the fact that the PolicyWrap myResilienceStrategy from above is just another Policy, which can be onward-wrapped too. // With this pattern, you can build an overall resilience strategy programmatically, reusing some common parts (eg PolicyWrap myResilienceStrategy) but varying other parts (eg Fallback) individually for different calls. PolicyWrap <String> policyWrap = fallbackForAnyException.Wrap(fallbackForCircuitBreaker.Wrap(myResilienceStrategy)); // For info: Equivalent to: PolicyWrap<String> policyWrap = Policy.Wrap(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable) { i++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string msg = policyWrap.Execute(() => client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteInColor("Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second Thread.Sleep(500); } Console.WriteLine(""); Console.WriteLine("Total requests made : " + i); Console.WriteLine("Requests which eventually succeeded : " + eventualSuccesses); Console.WriteLine("Retries made to help achieve success : " + retries); Console.WriteLine("Requests failed early by broken circuit : " + eventualFailuresDueToCircuitBreaking); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }
public async Task <InternalPersonDetails> GetPersonName(string personId, string apiKey, string largegroupid, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { return(await MakePersonNameRequest(personId, apiKey, largegroupid, requestId, policy)); }
public static void Execute() { Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); Console.WriteLine("======="); // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. var client = new WebClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToCircuitBreaking = 0; int eventualFailuresForOtherReasons = 0; // define wait and retry policy var waitAndRetryPolicy = Policy.Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering. We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForever( sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(200), // wait 200ms between each try onRetry: (exception, calculatedWaitDuration) => { // this is the new exception handler ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // define circuit breaker policy. Break if the action fails 4 times in a row var circuitBreakerPolicy = Policy.Handle <Exception>().CircuitBreaker( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + " ms!", ConsoleColor.Magenta); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss") + "]" + "..due to: " + ex.Message, ConsoleColor.Magenta); }, onReset: () => ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Call ok! Closed the circuit again!", ConsoleColor.Magenta), onHalfOpen: () => ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + ".Breaker logging: Half-open: Next call is a trial!", ConsoleColor.Magenta) ); PolicyWrap policyWrap = Policy.Wrap(waitAndRetryPolicy, circuitBreakerPolicy); int i = 0; // Do the following until a key is pressed while (!Console.KeyAvailable) { i++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string msg = policyWrap.Execute <String>(() => { return(client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); }); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + " (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); ConsoleHelper.WriteInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "Request " + i + " failed with: " + b.GetType().Name, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); ConsoleHelper.WriteLineInColor("[" + DateTime.Now.ToString("hh:mm:ss.fff") + "]" + "Request " + i + " eventually failed with: " + e.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } // Wait half second Thread.Sleep(500); } Console.WriteLine(""); Console.WriteLine("Total requests made : " + i); Console.WriteLine("Requests which eventually succeeded : " + eventualSuccesses); Console.WriteLine("Retries made to help achieve success: " + retries); Console.WriteLine("Requests failed early by broken circuit : " + eventualFailuresDueToCircuitBreaking); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <DemoProgress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. eventualSuccesses = 0; retries = 0; eventualFailuresDueToCircuitBreaking = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(AsyncDemo07_WaitAndRetryNestingCircuitBreakerUsingPolicyWrap).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(String.Empty)); // Define our waitAndRetry policy: keep retrying with 200ms gaps. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Exception filtering! We don't retry if the inner circuit-breaker judges the underlying system is out of commission! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { // This is your new exception handler! // Tell the user what they've won! progress.Report(ProgressWithMessage(".Log,then retry: " + exception.Message, Color.Yellow)); retries++; }); // Define our CircuitBreaker policy: Break if the action fails 4 times in a row. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { progress.Report(ProgressWithMessage(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta)); progress.Report(ProgressWithMessage("..due to: " + ex.Message, Color.Magenta)); }, onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Call ok! Closed the circuit again!", Color.Magenta)), onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: Next call is a trial!", Color.Magenta)) ); // New for demo07: combine the waitAndRetryPolicy and circuitBreakerPolicy into a PolicyWrap. PolicyWrap policyWrap = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); using (var client = new HttpClient()) { totalRequests = 0; bool internalCancel = false; // Do the following until a key is pressed while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; Stopwatch watch = new Stopwatch(); watch.Start(); try { // Retry the following call according to the policy wrap string response = await policyWrap.ExecuteAsync <String>(ct => { // This code is executed through both policies in the wrap: WaitAndRetry outer, then CircuitBreaker inner. Demo 06 shows a broken-out version of what this is equivalent to. return(client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests)); }, cancellationToken); watch.Stop(); // Display the response message on the console progress.Report(ProgressWithMessage("Response : " + response + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (BrokenCircuitException b) { watch.Stop(); progress.Report(ProgressWithMessage("Request " + totalRequests + " failed with: " + b.GetType().Name + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToCircuitBreaking++; } catch (Exception e) { watch.Stop(); progress.Report(ProgressWithMessage("Request " + totalRequests + " eventually failed with: " + e.Message + " (after " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } // Wait half second await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddOptions(); services.AddApiVersioning( o => { o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = new ApiVersion(1, 0); }); var azureStorageSettings = GetSettings <AzureStorageSettings>(); var notificationServiceSettings = GetSettings <NotificationServiceSettings>(); var faultToleranceSettings = GetSettings <FaultToleranceSettings>(); services.AddSingleton <IMetricsClient>(context => { var metricsClientFactory = new MetricsClientFactory(context.GetRequiredService <ILoggerFactory>(), TimeSpan.FromSeconds(15)); return(metricsClientFactory.CreateMetricsClient <LoggerMetricsClient>()); }); TimeoutPolicy timeoutPolicy = Policy.Timeout(faultToleranceSettings.TimeoutLength, TimeoutStrategy.Pessimistic); CircuitBreakerPolicy circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreaker( exceptionsAllowedBeforeBreaking: faultToleranceSettings.ExceptionsAllowedBeforeBreaking, durationOfBreak: TimeSpan.FromMinutes(faultToleranceSettings.DurationOfBreakInMinutes) ); PolicyWrap policyWrap = Policy.Wrap(circuitBreakerPolicy, timeoutPolicy); services.AddSingleton <ISyncPolicy>(policyWrap); QueueClient queueClient = new QueueClient(notificationServiceSettings.ServiceBusConnectionString, notificationServiceSettings.QueueName); ServiceBusNotificationServiceClient notificationService = new ServiceBusNotificationServiceClient(queueClient); services.AddSingleton <INotificationService>(context => new NotificationServiceMetricsDecorator( new NotificationServiceFaultToleranceDecorator( notificationService, context.GetRequiredService <ISyncPolicy>()), context.GetRequiredService <IMetricsClient>())); AzureCloudTable profileCloudTable = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.ProfilesTableName); AzureTableProfileStore profileStore = new AzureTableProfileStore(profileCloudTable); services.AddSingleton <IProfileStore>(context => new ProfileStoreMetricsDecorator( new ProfileStoreFaultToleranceDecorator( profileStore, context.GetRequiredService <ISyncPolicy>()), context.GetRequiredService <IMetricsClient>())); AzureCloudTable messagesCloudTable = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.MessagesTableName); AzureTableMessagesStore messagesStore = new AzureTableMessagesStore(messagesCloudTable); services.AddSingleton <IMessagesStore>(context => new MessagesStoreMetricsDecorator( new MessagesStoreFaultToleranceDecorator( messagesStore, context.GetRequiredService <ISyncPolicy>()), context.GetRequiredService <IMetricsClient>())); AzureCloudTable conversationsCloudTable = new AzureCloudTable(azureStorageSettings.ConnectionString, azureStorageSettings.UsersTableName); AzureTableConversationsStore conversationsStore = new AzureTableConversationsStore(conversationsCloudTable, messagesStore); services.AddSingleton <IConversationsStore>(context => new ConversationStoreMetricsDecorator( new ConversationsStoreFaultToleranceDecorator( conversationsStore, context.GetRequiredService <ISyncPolicy>()), context.GetRequiredService <IMetricsClient>())); services.AddSingleton <IConversationService>(context => new ConversationServiceMetricsDecorator( new ConversationService( context.GetRequiredService <IConversationsStore>(), context.GetRequiredService <ILogger <ConversationService> >(), context.GetRequiredService <INotificationService>()), context.GetRequiredService <IMetricsClient>())); services.AddLogging(); services.AddMvc(); }
public static void Execute() { Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); Console.WriteLine("======="); // Let's call a web api service to make repeated requests to a server. // The service is programmed to fail after 3 requests in 5 seconds. var client = new WebClient(); int eventualSuccesses = 0; int retries = 0; int eventualFailuresDueToTimeout = 0; int eventualFailuresForOtherReasons = 0; Stopwatch watch = null; // Define our timeout policy: time out after 2 seconds. We will use the pessimistic timeout strategy, which forces a timeout - even when the underlying delegate doesn't support it. var timeoutPolicy = Policy .Timeout(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic); // Define our waitAndRetry policy: keep retrying with 4 second gaps. This is (intentionally) too long: to demonstrate that the timeout policy will time out on this before waiting for the retry. RetryPolicy waitAndRetryPolicy = Policy .Handle <Exception>() .WaitAndRetryForever( attempt => TimeSpan.FromSeconds(4), (exception, calculatedWaitDuration) => { ConsoleHelper.WriteLineInColor(".Log,then retry: " + exception.Message, ConsoleColor.Yellow); retries++; }); // Define a fallback policy: provide a nice substitute message to the user, if we found the call was rejected due to the timeout policy. FallbackPolicy <String> fallbackForTimeout = Policy <String> .Handle <TimeoutRejectedException>() .Fallback( fallbackValue: /* Demonstrates fallback value syntax */ "Please try again later [Fallback for timeout]", onFallback: b => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches failed with: " + b.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresDueToTimeout++; } ); // Define a fallback policy: provide a substitute string to the user, for any exception. FallbackPolicy <String> fallbackForAnyException = Policy <String> .Handle <Exception>() .Fallback( fallbackAction: /* Demonstrates fallback action/func syntax */ () => { return("Please try again later [Fallback for any exception]"); }, onFallback: e => { watch.Stop(); ConsoleHelper.WriteInColor("Fallback catches eventually failed with: " + e.Exception.Message, ConsoleColor.Red); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Red); eventualFailuresForOtherReasons++; } ); // Compared to previous demo08: here we use *instance* wrap syntax, to wrap all in one go. PolicyWrap <String> policyWrap = fallbackForAnyException.Wrap(fallbackForTimeout).Wrap(timeoutPolicy).Wrap(waitAndRetryPolicy).Wrap(waitAndRetryPolicy); int i = 0; while (!Console.KeyAvailable) { i++; watch = new Stopwatch(); watch.Start(); try { // Manage the call according to the whole policy wrap. string msg = policyWrap.Execute(() => client.DownloadString(Configuration.WEB_API_ROOT + "/api/values/" + i)); watch.Stop(); // Display the response message on the console ConsoleHelper.WriteInColor("Response : " + msg, ConsoleColor.Green); ConsoleHelper.WriteLineInColor(" (after " + watch.ElapsedMilliseconds + "ms)", ConsoleColor.Green); eventualSuccesses++; } catch (Exception e) // try-catch not needed, now that we have a Fallback.Handle<Exception>. It's only been left in to *demonstrate* it should never get hit. { throw new InvalidOperationException("Should never arrive here. Use of fallbackForAnyException should have provided nice fallback value for any exceptions.", e); } // Wait half second Thread.Sleep(500); } Console.WriteLine(""); Console.WriteLine("Total requests made : " + i); Console.WriteLine("Requests which eventually succeeded : " + eventualSuccesses); Console.WriteLine("Retries made to help achieve success : " + retries); Console.WriteLine("Requests timed out by timeout policy : " + eventualFailuresDueToTimeout); Console.WriteLine("Requests which failed after longer delay: " + eventualFailuresForOtherReasons); }