public async Task SetAsync( string key, T item, TimeSpan expiration) { var result = await _setFallBack .ExecuteAsync(async() => await SetAsyncInner(key, item, expiration) .ConfigureAwait(false)) .ConfigureAwait(false); if (result) { if (_debugLoggingEnabled) { _logger.LogDebug( $"Cache insert operation successful for {key}"); } } else { if (_errorLoggingEnabled) { _logger.LogDebug( $"Caching problems when setting {key}"); } } }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Yield(); // https://github.com/dotnet/extensions/issues/2149 while (!stoppingToken.IsCancellationRequested) { if (_queue.Messages.Count > _maxQueue) { _queue.Messages.Clear(); _logger.LogWarning($"Dumped {_maxQueue} logs in queue."); } if (_queue.Messages.TryDequeue(out HttpLogEntry message)) { try { await _policy.ExecuteAsync(async() => await _service.PostLogAsync(JsonSerializer.Serialize(message), stoppingToken)); } catch (Exception e) when( e is HttpRequestException || e is OperationCanceledException || e is BrokenCircuitException) { if (Enum.Parse <LogLevel>(message.LogLevel) > LogLevel.Debug) { _queue.Messages.Enqueue(message); } } } } }
public override async Task <TReturn> HandleExceptionAsync <TReturn>(Func <CancellationToken, Task <TReturn> > func, CancellationToken funcCancellationToken = default, Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default) { Task <TReturn> returnValue = default; try { var returnValueFromFunc = await func(funcCancellationToken); if (returnValueFromFunc is Task <TReturn> ) { returnValue = returnValueFromFunc as Task <TReturn>; } else { returnValue = Task.FromResult(returnValueFromFunc); } } catch (Exception ex) { returnValue = await ExceptionHandlingUtility.WrapFuncWithExceptionHandling(async() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { AsyncPolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); return(await policyWrap.ExecuteAsync(func, funcCancellationToken) as Task <TReturn>); } return(default(Task <TReturn>)); }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } return(await returnValue); }
public void Should_retry_until_threshold_is_reached() { AsyncCircuitBreakerPolicy breaker = Policy .Handle <Exception>() .CircuitBreakerAsync(3, TimeSpan.FromMilliseconds(1000), OnBreak, OnReset); AsyncPolicyWrap retryPolicy = Policy.Handle <Exception>().RetryAsync(3) .WrapAsync(breaker); //var policy = Policy // .Handle<TaskCanceledException>() // .Or<FailedConnectionToBankException>() // .FallbackAsync(cancel => ReturnWillHandleLater(payment.GatewayPaymentId, payment.RequestId)) // .WrapAsync(breaker); int count = 0; retryPolicy.ExecuteAsync(async() => { Console.WriteLine(count++); await Task.FromException(new Exception()); }); }
public async Task <T> GetAsync(string key) { try { if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentNullException(nameof(key)); } var cacheKey = GetKey(key); string json = await _getFallBack .ExecuteAsync(async() => await Task.Run( () => _handle.cache.Get <string>(cacheKey)) .ConfigureAwait(false) ) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(json)) { if (_debugLoggingEnabled) { _logger.LogDebug( "Cache Miss: No item with key {key} in NCache", key); } return(null); } else if (json.Equals(CacheHandle.CACHE_PROBLEMS)) { if (_errorLoggingEnabled) { _logger.LogError( $"Cache problems when accessing {key}"); } return(null); } else { if (_debugLoggingEnabled) { _logger.LogDebug( "Cache Hit: Item with key {key} found in NCache", key); } return(_serializer.Deserialize <T>(json)); } } catch (Exception ex) { if (_errorLoggingEnabled) { _logger.LogError( ex, $"Something wrong with GetAsync for key {key}"); } throw; } }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = await Policy.ExecuteAsync( async() => { Log.Information("sending request to {@Uri}...", request.RequestUri); return(await base.SendAsync(request, cancellationToken).ConfigureAwait(false)); } ).ConfigureAwait(false); return(response); }
public async Task <bool> Handle(ChargePatientCommand request, CancellationToken cancellationToken) { return(await _policyWrap.ExecuteAsync(async() => { var result = await _customer.Charge(300); if (result == false) { throw new HttpRequestException("This is a fake request Exception"); } return true; })); }
/// <inheritdoc /> public async Task <(Stream stream, string mediaType)> FetchAsync(Uri fetchUri) { var stopwatch = Stopwatch.StartNew(); var policyContext = new Context(fetchUri.ToString()); _logger.LogDebug("Start fetch request to {url}", fetchUri); using (var response = await _timeoutWithRetryPolicy.ExecuteAsync(FetchAction, policyContext, CancellationToken.None)) { stopwatch.Stop(); _fetchDurationMsMetric.Labels(fetchUri.Host).Observe(stopwatch.ElapsedMilliseconds); _logger.LogDebug("Fetch request executed in {elapsedMs} ms", stopwatch.ElapsedMilliseconds); if (!response.IsSuccessStatusCode) { _fetchErrorsMetric.Inc(); var content = await response.Content.ReadAsStringAsync(); _logger.LogError("Got status {status} on {method} request to {url} with content: {content}", response.StatusCode, HttpMethod.Get, fetchUri, content); throw new FetchRequestException(response.StatusCode, content); } if (response.Content.Headers.ContentLength > _maxBinarySize) { throw new FetchResponseTooLargeException(response.Content.Headers.ContentLength.Value); } if (string.IsNullOrEmpty(response.Content.Headers.ContentType.MediaType)) { throw new FetchResponseContentTypeInvalidException("Content type in response is not specified"); } var memoryStream = new MemoryStream(); using (var responseStream = await response.Content.ReadAsStreamAsync()) { int readBytes; var buffer = new byte[StreamCopyBufferSize]; do { readBytes = await responseStream.ReadAsync(buffer, 0, buffer.Length); await memoryStream.WriteAsync(buffer, 0, readBytes); if (memoryStream.Length > _maxBinarySize) { throw new FetchResponseTooLargeException(memoryStream.Length); } }while (readBytes > 0); } return(memoryStream, response.Content.Headers.ContentType.MediaType); } }
public async Task <ActionResult <IEnumerable <Team> > > GetSomeData(CancellationToken cancellationToken) { Context context = new Context(nameof(GetSomeData)).WithChaosSettings(chaosSettings); retries = 0; //https://github.com/PawelGerr/EntityFrameworkCore-Demos/blob/master/src/EntityFramework.Demo/Demos/NamedTransactionsDemo.cs //catch (InvalidOperationException ex) when ((ex.InnerException?.InnerException is SqlException sqlEx) && sqlEx.Number == 1205) var fault = new InvalidOperationException("Simmy injected a deadlockException"); var chaosPolicy = MonkeyPolicy.InjectExceptionAsync(with => with.Fault(fault) .InjectionRate(0.95) .Enabled() ); var retryPolicy = Policy.Handle <Exception>().WaitAndRetryAsync( 3, // Retry 3 times attempt => TimeSpan.FromMilliseconds(200), // Wait 200ms between each try. (exception, calculatedWaitDuration) => // Capture some info for logging! { // This is your new exception handler! // Tell the user what they've won! _logger.LogWarning(EventIds.DBReadFailure, exception, "hit an exception"); retries++; }); AsyncPolicyWrap faultAndRetryWrap = Policy.WrapAsync(retryPolicy, chaosPolicy); try { // Retry the following call according to the policy - 3 times. var something = await faultAndRetryWrap.ExecuteAsync <List <Team> >( async (context, cancellationToken) => // The Execute() overload takes a CancellationToken, but it happens the executed code does not honour it. { // This code is executed within the Policy var corr = context.CorrelationId; // Make a request and get a response // Display the response message on the console _logger.LogDebug("Getting some data: "); return(await _context.Teams.ToListAsync()); } , context , cancellationToken // The cancellationToken passed in to Execute() enables the policy instance to cancel retries, when the token is signalled. ); return(something); } catch (Exception e) { _logger.LogError("Request eventually failed with: " + e.Message); } return(BadRequest()); }
private async Task <IEnumerable <SyndicationItem> > TryReadFeed(IAmACommunityMember tamarin, string feedUri, Func <SyndicationItem, bool> filter) { try { return(await policy.ExecuteAsync(context => ReadFeed(feedUri, filter), new Context(feedUri)).ConfigureAwait(false)); } catch (FeedReadFailedException ex) { Logger.Error(ex, $"{tamarin.FirstName} {tamarin.LastName}'s feed of {ex.Data["FeedUri"]} failed to load."); } return(new SyndicationItem[0]); }
public async Task <ResponseObject> GetAsync(Uri url, string token) { _client.DefaultRequestHeaders.Authorization = getBearerAuthorization(token); var response = await policies.ExecuteAsync(() => _client.GetAsync(url)); return(manageResponse(response)); }
public async Task <ServiceResponse <T> > ExecuteRequest <T>(string baseUrl, string path, Method method, object body = null, List <RequestParameter> parameters = null, List <RequestHeader> headers = null, AsyncPolicyWrap <IRestResponse <T> > policy = null) where T : new() { var client = new RestClient(baseUrl) { Timeout = RequestTimeout * 1000 }; var request = ConfigureRequest(path, method, body, parameters, headers); var fullUrl = client.BuildUri(request); IRestResponse <T> response = null; if (policy == null) { response = await client.ExecuteTaskAsync <T>(request); } else { Context context = new Context().WithLogger(_logger); response = await policy.ExecuteAsync(ctx => client.ExecuteTaskAsync <T>(request), context); } //var cb = policy.GetPolicies(); string responseErr = null; ServiceResponseException responseEx = null; HttpStatusCode responseCode = response.StatusCode; if (!response.IsSuccessful) { response.Data = default; responseErr = !string.IsNullOrWhiteSpace(response.ErrorMessage) ? response.ErrorMessage : response.Content; if (response.ResponseStatus == ResponseStatus.TimedOut) { responseCode = HttpStatusCode.GatewayTimeout; } LogFailedRequest(response.ErrorException, responseCode, responseErr, fullUrl.ToString()); if (!string.IsNullOrWhiteSpace(responseErr) || response.ErrorException != null) { responseEx = new ServiceResponseException(response.StatusCode, responseErr, response.ErrorException); } } return(new ServiceResponse <T>(response.Data, response, responseCode, response.IsSuccessful, responseErr, responseEx)); }
private static async Task WaitForTransmissionAsync() { var torrentClient = DIContainer.Default.Get <ITorrentClient>(); try { await _WaitForHealthyPolicy.ExecuteAsync(async() => { await torrentClient.GetAllTorrentsAsync().ConfigureAwait(false); }).ConfigureAwait(false); } catch (Polly.Timeout.TimeoutRejectedException e) { throw new ApplicationException("Timed out while waiting on the torrent client", e); } }
public async Task <IActionResult> Index() { var recommendationsTask = fallback.ExecuteAsync(() => _client.GetStringAsync(_config.GetValue <string>("externalRestServices:recommendationService"))); var viewedItemsTask = _client.GetStringAsync(_config.GetValue <string>("externalRestServices:viewedItemsService")); var cartTask = _client.GetStringAsync(_config.GetValue <string>("externalRestServices:cartService")); var customerTask = _client.GetStringAsync(_config.GetValue <string>("externalRestServices:customerService")); var response = await Task.WhenAll(recommendationsTask, viewedItemsTask, cartTask, customerTask); CompositeModel model = new CompositeModel { Recommendations = JsonConvert.DeserializeObject <IEnumerable <Item> > (response[0]), ViewedItems = JsonConvert.DeserializeObject <IEnumerable <Item> > (response[1]), CartItems = JsonConvert.DeserializeObject <IEnumerable <Item> > (response[2]), Customers = JsonConvert.DeserializeObject <IEnumerable <Customer> > (response[3]) }; return(View(model)); }
public async Task <T> MakeRequestAsync <T>(Task <T> request, AsyncPolicyWrap policy) where T : Status { T response = (T)Activator.CreateInstance(typeof(T)); if (!CrossConnectivity.Current.IsConnected) { response.ErrorCode = ""; response.ErrorMessage = ErrorMessageConstants.DEVICE_CONNECTIVITY_ERROR; response.IsSuccess = false; } else { try { response = await policy.ExecuteAsync(async() => await request); response.IsSuccess = true; } catch (AggregateException e) { foreach (var nestedException in e.InnerExceptions) { response.ErrorCode = ""; response.ErrorMessage = nestedException.Message; response.IsSuccess = false; } } catch (ApiException e) { response.ErrorCode = e.StatusCode.ToString(); response.ErrorMessage = e.Message; response.IsSuccess = false; } catch (Exception e) { response.ErrorCode = ""; response.ErrorMessage = e.Message; response.IsSuccess = false; } } return(response); }
public override async Task HandleExceptionAsync(Func <CancellationToken, Task> action, CancellationToken actionCancellationToken = default, Func <CancellationToken, Task> onExceptionCompensatingHandler = null, CancellationToken onExceptionCompensatingHandlerCancellationToken = default) { try { await action(actionCancellationToken); } catch (Exception ex) { ExceptionHandlingUtility.WrapActionWithExceptionHandling(async() => { if (CheckIfExceptionsNeedsToBePollyHandled(ex)) { AsyncPolicyWrap policyWrap = GetPolicyWrapWithProperFallbackActionSetForFallbackPoliciesAsync(ex, onExceptionCompensatingHandler); await policyWrap.ExecuteAsync(action, actionCancellationToken); } }, _logger); await HandleExceptionWithThrowCondition(ex, onExceptionCompensatingHandler, onExceptionCompensatingHandlerCancellationToken); } }
public async Task <IActionResult> GetProduct(int productId) { var httpClient = new HttpClient { BaseAddress = new Uri("https://localhost:44363/") }; var contextDictionary = new Dictionary <string, object> { { "Logging", "Enabled" } }; var catalogContext = new Context("CatalogContext", contextDictionary); // Without polly //var response = await httpClient.GetAsync($"api/inventories/{productId}"); // With Polly (Retry) // var response = await _httpRetryPolicy.ExecuteAsync(() => httpClient.GetAsync($"api/inventories/{productId}")); // With Polly (Wait and Retry) // var response = await _httpWaitAndRetryPolicy.ExecuteAsync(() => httpClient.GetAsync($"api/inventories/{productId}")); // With Polly (Fallback and Retry) // var response = await _fallbackPolicy.ExecuteAsync(async () => // await _httpRetryPolicy.ExecuteAsync(() => httpClient.GetAsync($"api/inventories/{productId}"))); // With Polly (Fallback, Retry and timeout) - Manual Wrap //var response = await // _fallbackPolicy.ExecuteAsync(() => // _httpRetryPolicy.ExecuteAsync(() => // _timeoutPolicy.ExecuteAsync(async (token) => await httpClient.GetAsync($"api/inventories/{productId}", token), cancellationToken: CancellationToken.None))); // With Polly and Wrap // var response = await _policyWrap.ExecuteAsync(() => httpClient.GetAsync($"api/inventories/{productId}", CancellationToken.None)); // With Polly and context var response = await _policyWrap.ExecuteAsync((context) => httpClient.GetAsync($"api/inventories/{productId}", CancellationToken.None), catalogContext); var result = await response.Content.ReadAsStringAsync(); return(new OkObjectResult(result)); }
/// <summary> /// Calls the dynamic service and returns the result. /// </summary> /// <param name="serviceInfo">Information about the service to call</param> /// <param name="cacheRegion">The cache region to look for values for post parameters under in</param> /// <param name="cancellationToken">Cancellation token to cancel the request</param> /// <param name="additionalParameters">Additional post parameters to include in the request body</param> /// <returns>A service response representing the result of the call to the dynamic service</returns> protected override async Task <ServiceResponse> CallServiceInternal(CalledServiceInfo serviceInfo, string cacheRegion, CancellationToken cancellationToken, IEnumerable <KeyValuePair <string, string> > additionalParameters) { var serviceResponse = new ServiceResponse { ServiceId = serviceInfo.Id }; try { AsyncPolicyWrap <ServiceResponse> breaker = GetCircuitBreakerPolicy(serviceInfo); return(await breaker.ExecuteAsync(async (cancelToken) => { IEnumerable <KeyValuePair <string, string> > postParameters = GetPostParameters(serviceInfo, cacheRegion, additionalParameters); HttpClientResponse response = await _httpClientWrapper.PostAsync(serviceInfo.Endpoint, postParameters, cancelToken); if (response.HttpStatusCode.IsOkStatus()) { serviceResponse.Value = response.Response; serviceResponse.Status = ServiceResponseStatus.Success; serviceResponse.TokenResponses = _tokenService.ParseTokens(cacheRegion, response.Response, serviceInfo.Tokens).ToArray(); } else { serviceResponse.Status = ServiceResponseStatus.Error; } return serviceResponse; }, cancellationToken : cancellationToken)); } catch (Exception) { serviceResponse.Status = ServiceResponseStatus.Error; return(serviceResponse); } }
public async Task <IActionResult> Get(int id) { var httpClient = GetHttpClient(); string requestEndpoint = $"samples/mix-generic-and-non/inventory/{id}"; var response = await _policyWrap.ExecuteAsync(token => httpClient.GetAsync(requestEndpoint, token), CancellationToken.None); if (response.IsSuccessStatusCode) { var itemsInStock = JsonConvert.DeserializeObject <int>(await response.Content.ReadAsStringAsync()); return(Ok(itemsInStock)); } if (response.Content != null) { return(StatusCode((int)response.StatusCode, response.Content.ReadAsStringAsync())); } return(StatusCode((int)response.StatusCode)); }
/// <summary> /// Removes the specified cacheKey async. /// </summary> /// <returns>The async.</returns> /// <param name="cacheKey">Cache key.</param> public async Task RemoveAsync(string cacheKey) { ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey)); try { // distributed cache at first await _distributedCache.RemoveAsync(cacheKey); } catch (Exception ex) { LogMessage($"remove cache key [{cacheKey}] error", ex); } await _localCache.RemoveAsync(cacheKey); // send message to bus await _busAsyncWrap.ExecuteAsync(async() => await _bus.PublishAsync(_options.TopicName, new EasyCachingMessage { Id = _cacheId, CacheKeys = new string[] { cacheKey } })); }
public async Task <GetOffersResult> GetOffers(OfferTypes?type, string searchCommand, int?page, int?pageSize, CancellationToken cancellationToken) { // Build request URL pageSize ??= _options.DefaultPageSize; pageSize = Math.Min(pageSize.Value, MaxPageSize); var parameters = new List <string>() { $"page={page ?? DefaultPage}", $"PageSize={pageSize}" }; if (type != null) { var typeString = FirstCharLower($"{type}"); parameters.Add($"type={typeString}"); } if (searchCommand != null) { parameters.Add($"zo={searchCommand}"); } var requestUrl = BuildRequestUrl("/feeds/Aanbod.svc", parameters); // Make request using var response = await _retryPolicy.ExecuteAsync(async () => await _httpClient.GetAsync(requestUrl, cancellationToken)); // Get content from response body var contentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var content = new { Objects = new[] { new { Id = default(Guid), MakelaarId = default(int), MakelaarNaam = default(string), } }, Paging = new { AantalPaginas = default(int), HuidigePagina = default(int), }, TotaalAantalObjecten = default(int) }; content = JsonConvert.DeserializeAnonymousType(contentString, content); var result = new GetOffersResult(); // Build result from content if (content != null) { result.Paging = new PagingInfo { TotalPages = content.Paging.AantalPaginas, CurrentPage = content.Paging.HuidigePagina, }; result.TotalObjects = content.TotaalAantalObjecten; if (content.Objects != null) { result.Offers = content.Objects.Select(o => new Offer { Id = o.Id, MakelaarId = o.MakelaarId, MakelaarNaam = o.MakelaarNaam, }); } } return(result); }
private async Task <IActionResult> ProxyTo(string url) => await _policy.ExecuteAsync(async() => Content(await _httpClient.GetStringAsync(url)));
/// <summary> /// This method performs the call to the cached service if no value is available in the cache. /// </summary> /// <param name="serviceInfo">Information about the service to call</param> /// <param name="cacheRegion">The cache region to look for an existing response and to look for values for post parameters under in</param> /// <param name="cancellationToken">Cancellation token to cancel the request</param> /// <param name="additionalParameters">Additional post parameters to include in the request body</param> /// <returns>A service response representing the result of the call to the cached service</returns> protected override async Task <ServiceResponse> CallServiceInternal(CalledServiceInfo serviceInfo, string cacheRegion, CancellationToken cancellationToken, IEnumerable <KeyValuePair <string, string> > additionalParameters) { SemaphoreSlim semaphore = _semaphores.GetOrAdd($"{cacheRegion}-{serviceInfo.CacheKey}", _ => new SemaphoreSlim(1, 1)); try { await semaphore.WaitAsync(cancellationToken); if (cancellationToken.IsCancellationRequested) { return(new ServiceResponse { ServiceId = serviceInfo.Id, Status = ServiceResponseStatus.Timeout }); } CacheEntry <string> cacheResult = Cache.Get <string>(cacheRegion, serviceInfo.CacheKey); if (cacheResult != null) { Log.Debug("Read value for service {ServiceName} from cache. Entry has value: {HasValue}", serviceInfo.Name, cacheResult.Value != null); ServiceResponse serviceResponse = new ServiceResponse { ServiceId = serviceInfo.Id, Status = ServiceResponseStatus.Success, Value = cacheResult.Value }; if (string.IsNullOrEmpty(serviceResponse.Value)) { return(serviceResponse); } serviceResponse.TokenResponses = _tokenService.ParseTokens(cacheRegion, cacheResult.Value, serviceInfo.Tokens); foreach (TokenResponse token in serviceResponse.TokenResponses) { Cache.Set(cacheRegion, token.CacheKey, token.Value); } return(serviceResponse); } AsyncPolicyWrap <ServiceResponse> breaker = GetCircuitBreakerPolicy(serviceInfo); return(await breaker.ExecuteAsync(async (cancelToken) => { IEnumerable <KeyValuePair <string, string> > postParameters = GetPostParameters(serviceInfo, cacheRegion, additionalParameters); HttpClientResponse response = await _httpClientWrapper.PostAsync(serviceInfo.Endpoint, postParameters, cancelToken); var serviceResponse = new ServiceResponse { ServiceId = serviceInfo.Id }; if (response.HttpStatusCode.IsOkStatus()) { serviceResponse.Value = response.Response; serviceResponse.Status = ServiceResponseStatus.Success; serviceResponse.TokenResponses = _tokenService.ParseTokens(cacheRegion, response.Response, serviceInfo.Tokens); foreach (TokenResponse token in serviceResponse.TokenResponses) { Cache.Set(cacheRegion, token.CacheKey, token.Value); } Cache.Set(cacheRegion, serviceInfo.CacheKey, response.Response); } else { Cache.Set <string>(cacheRegion, serviceInfo.CacheKey, null); serviceResponse.Status = ServiceResponseStatus.Error; } return serviceResponse; }, cancellationToken : cancellationToken)); } catch (TaskCanceledException) { return(new ServiceResponse { ServiceId = serviceInfo.Id, Status = ServiceResponseStatus.Timeout }); } finally { if (semaphore.CurrentCount == 0) { semaphore.Release(); } } }
public async Task ExecuteAsync(Func <Task> operation, CancellationToken cancellationToken = default) { await _asyncRetryPolicy.ExecuteAsync(operation); }
protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => _circuitBreakerPolicy .ExecuteAsync( async ct => await base.SendAsync(request, ct), cancellationToken);
private Task <T> HttpInvoker <T>(Func <Task <T> > action) => // Executes the action applying all // the policies defined in the wrapper _policyWrapper.ExecuteAsync(() => action());
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress <Progress> progress) { if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } if (progress == null) { throw new ArgumentNullException(nameof(progress)); } // Llama el servicio web de la API para hacer peticiones repetitivas al servidor. // El servicio esta programado para fallar despues de 3 peticiones en 5 segundos. eventualSuccesses = 0; retries = 0; eventualFailuresDueToCircuitBreaking = 0; eventualFailuresForOtherReasons = 0; progress.Report(ProgressWithMessage(typeof(Wrap_Fallback_WaitAndRetry_CircuitBreaker_Async).Name)); progress.Report(ProgressWithMessage("======")); progress.Report(ProgressWithMessage(string.Empty)); Stopwatch watch = null; // Definimos nuestro waitAndRetry policy: sigue intentando con intervalos de 200ms. var waitAndRetryPolicy = Policy .Handle <Exception>(e => !(e is BrokenCircuitException)) // Filtrado de excepción! No reintentamos si el circuit-breaker determina que el sistema invocado está fuera de servicio! .WaitAndRetryForeverAsync( attempt => TimeSpan.FromMilliseconds(200), (exception, calculatedWaitDuration) => { progress.Report(ProgressWithMessage(".Log,vuelva e intentar: " + exception.Message, Color.Yellow)); retries++; }); // Definimos nuestro CircuitBreaker policy: cortar si la acción falla 4 veces seguidas. var circuitBreakerPolicy = Policy .Handle <Exception>() .CircuitBreakerAsync( exceptionsAllowedBeforeBreaking: 4, durationOfBreak: TimeSpan.FromSeconds(3), onBreak: (ex, breakDelay) => { progress.Report(ProgressWithMessage(".Breaker logging: Cortando el circuito por " + breakDelay.TotalMilliseconds + "ms!", Color.Magenta)); progress.Report(ProgressWithMessage("..debido a: " + ex.Message, Color.Magenta)); }, onReset: () => progress.Report(ProgressWithMessage(".Breaker logging: Llamado ok! Se cierra el circuito nuevamente!", Color.Magenta)), onHalfOpen: () => progress.Report(ProgressWithMessage(".Breaker logging: Half-open: el proximo llamado es de prueba!", Color.Magenta)) ); // Definimos un fallback policy: provee un buen mensaje de reemplazo para el usuario, si encontramos que el circuito estaba cortado. AsyncFallbackPolicy <string> fallbackForCircuitBreaker = Policy <string> .Handle <BrokenCircuitException>() .FallbackAsync( fallbackValue: "Por favor intente mas tarde [mensaje substituido por fallback policy]", onFallbackAsync: async b => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback capto llamada fallida por: " + b.Exception.Message + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresDueToCircuitBreaking++; } ); // Definimos un fallback policy: provee un buen mensaje substituto para el usuario, para cualquier excepcion. AsyncFallbackPolicy <string> fallbackForAnyException = Policy <string> .Handle <Exception>() .FallbackAsync( fallbackAction: async ct => { await Task.FromResult(true); /* logica extra que se desee aquí */ return("Por favor intente mas tarde [Fallback para cualquier excepción]"); }, onFallbackAsync: async e => { await Task.FromResult(true); watch.Stop(); progress.Report(ProgressWithMessage("Fallback captura eventualmented fallido por: " + e.Exception.Message + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Red)); eventualFailuresForOtherReasons++; } ); // Combinamos el waitAndRetryPolicy y circuitBreakerPolicy en un PolicyWrap AsyncPolicyWrap myResilienceStrategy = Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicy); // Envuelve los dos fallback policies en el frente del wrap existente. Demuestra el hecho de que el PolicyWrap myResilienceStrategy de arriba es solo otro Policy, el cual puede ser envuelto también. // Con este patron, se puede construir una estrategia general programaticamente, reusando algunas partes en común (ej. Policy Wrap myResilienceStrategy) pero variendo otras partes (ej. Fallback) individualmente para diferentes llamados. AsyncPolicyWrap <string> policyWrap = fallbackForAnyException.WrapAsync(fallbackForCircuitBreaker.WrapAsync(myResilienceStrategy)); // Para info: equivalente a: AsyncPolicyWrap<string> policyWrap = Policy.WrapAsync(fallbackForAnyException, fallbackForCircuitBreaker, waitAndRetryPolicy, circuitBreakerPolicy); totalRequests = 0; using (var client = new HttpClient()) { bool internalCancel = false; // Hacer lo siguiente hasta que una tecla sea presionada while (!internalCancel && !cancellationToken.IsCancellationRequested) { totalRequests++; watch = new Stopwatch(); watch.Start(); try { // Maneja el llamado acorde al policy wrap string response = await policyWrap.ExecuteAsync(ct => client.GetStringAsync(Configuration.WEB_API_ROOT + "/api/values/" + totalRequests), cancellationToken); watch.Stop(); // Muestra la respuesta en la consola progress.Report(ProgressWithMessage("Respuesta : " + response + " (despues de " + watch.ElapsedMilliseconds + "ms)", Color.Green)); eventualSuccesses++; } catch (Exception e) // try-catch innecesario ahora que tenemos un Fallback.Handle<Exception>. Sólo está aquí para demostrar que nunca llega hasta este codigo. { throw new InvalidOperationException("Nunca debería llegar hasta aquí. Uso de fallbackForAnyException debería proveer un buen mensaje devuelta al usuario para cualquier excepción.", e); } // Espera medio segundo await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; } } }
public async Task <string> GetGoodbyeMessage() { Trace.WriteLine($"Circuit State: {_circuitBreakerPolicy.CircuitState}"); return(await _policyWrap.ExecuteAsync(async() => await _messageRepository.GetGoodbyeMessage())); }
/// <inheritdoc/> public async Task <int> CountQueryAsync( string queryString, bool queryAll = false, CancellationToken cancellationToken = default) { var mContext = new Context { [_policyContextMethod] = nameof(CountQueryAsync) }; return(await _policy.ExecuteAsync( async (context, token) => { var client = _forceClient.Value().Result; return await client.CountQuery(queryString, queryAll); }, mContext, cancellationToken)); }
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. AsyncPolicyWrap 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; } } }