private CircuitBreaker MakeCircuitBreaker(IAdaptToBank bankAdapter, Payment payment) { var breaker = Policy .Handle <TaskCanceledException>() .Or <FailedConnectionToBankException>() .CircuitBreakerAsync(exceptionsAllowedBeforeBreaking: 3, durationOfBreak: TimeSpan.FromMilliseconds(40), onBreak: (exception, timespan, context) => { // When circuit breaker opens, buffer failed `PayingAttempt` _failureHandler.Buffer(bankAdapter, payment); }, onReset: context => { #pragma warning disable 4014 // Fire and forget (Polly OnReset does not provide awaitable signature) _failureHandler.ProcessBufferedPaymentRequest(); #pragma warning restore 4014 }); AsyncPolicyWrap policy = Policy.Handle <TaskCanceledException>() .Or <FailedConnectionToBankException>() .WaitAndRetryAsync(3, retry => TimeSpan.FromMilliseconds(Math.Pow(2, retry))) .WrapAsync(breaker); return(new CircuitBreaker(breaker, policy)); }
private async Task <bool> AttemptPaying(IAdaptToBank bankAdapter, Payment payment) { var payingAttempt = payment.MapToAcquiringBank(); var circuitBreaker = CircuitBreaker(bankAdapter, payment, payingAttempt); IBankResponse bankResponse = new NullBankResponse(); var policyResult = await circuitBreaker.Policy.ExecuteAndCaptureAsync(async() => { using (var cts = new CancellationTokenSource()) { var timeout = _timeoutProviderForBankResponseWaiting.GetTimeout(); cts.CancelAfter(timeout); bankResponse = await bankAdapter.RespondToPaymentAttempt(payingAttempt, cts.Token); } }); if (policyResult.FinalException == null) { circuitBreaker.Reset(); } else { return(false); } var strategy = BankResponseHandleStrategyBuilder.Build(bankResponse, _paymentsRepository); await strategy.Handle(_gatewayExceptionSimulator, bankResponse.GatewayPaymentId); return(true); }
public void Buffer(IAdaptToBank bankAdapter, Payment payment) { var payingAttempt = payment.MapToAcquiringBank(); _bankResponseProcessingLogger.LogInformation($"<------ Enqueue request {payingAttempt.PaymentRequestId}"); _buffer.Enqueue(new PaymentRequestBuffer(bankAdapter, payingAttempt, payment)); }
private CircuitBreaker CircuitBreaker(IAdaptToBank bankAdapter, Payment payment) { var bankAdapterType = bankAdapter.GetType(); if (!_circuitBreakers.TryGet(bankAdapterType, out CircuitBreaker circuitBreaker)) { circuitBreaker = MakeCircuitBreaker(bankAdapter, payment); _circuitBreakers.Add(bankAdapterType, circuitBreaker); } return(circuitBreaker); }
public async Task <IPaymentRequestHandlingResult> AttemptPaying(IAdaptToBank bankAdapter, Payment payment) { var payingAttempt = payment.MapToAcquiringBank(); var circuitBreaker = CircuitBreaker(bankAdapter, payment); IBankResponse bankResponse = new NullBankResponse(); var policyResult = await circuitBreaker.Policy.ExecuteAndCaptureAsync(async() => { using (var cts = new CancellationTokenSource()) { var timeout = _timeoutProviderForBankResponseWaiting.GetTimeout(); cts.CancelAfter(timeout); bankResponse = await bankAdapter.RespondToPaymentAttempt(payingAttempt, cts.Token); } }); if (policyResult.FinalException == null) { circuitBreaker.Reset(); } else if (policyResult.FinalException is BankDuplicatedPaymentIdException paymentDuplicatedException) { _logger.LogError(paymentDuplicatedException.Message); payment.HandleBankPaymentIdDuplication(); await _paymentsRepository.Save(payment, payment.Version); return(PaymentRequestHandlingStatus.Fail(payingAttempt.GatewayPaymentId, payingAttempt.PaymentRequestId, policyResult.FinalException, "Bank Duplicated PaymentId")); } var strategy = BankResponseHandleStrategyBuilder.Build(bankResponse, _paymentsRepository); await strategy.Handle(_gatewayExceptionSimulator, bankResponse.GatewayPaymentId); return(PaymentRequestHandlingStatus.Finished(payingAttempt.GatewayPaymentId, payingAttempt.PaymentRequestId)); }
public PaymentRequestBuffer(IAdaptToBank bankAdapter, PayingAttempt payingAttempt, Payment payment) { BankAdapter = bankAdapter; PayingAttempt = payingAttempt; Payment = payment; }