public async Task <TResult> ExecuteWithBreakerAsync <TResult>(AsyncCommand <TResult> command, CancellationToken ct) { var breaker = _circuitBreakerFactory.GetCircuitBreaker(command.BreakerKey); if (!breaker.IsAllowing()) { _metricEvents.RejectedByBreaker(breaker.Name, command.Name); throw new CircuitBreakerRejectedException(); } TResult result; var success = true; var breakerStopwatch = Stopwatch.StartNew(); var executionStopwatch = Stopwatch.StartNew(); try { // Await here so we can catch the Exception and track the state. result = await command.ExecuteAsync(ct).ConfigureAwait(false); executionStopwatch.Stop(); breaker.MarkSuccess(breakerStopwatch.ElapsedMilliseconds); breaker.Metrics.MarkCommandSuccess(); } catch (Exception e) { executionStopwatch.Stop(); success = false; if (_ignoredExceptions.IsExceptionIgnored(e.GetType())) { success = true; breaker.MarkSuccess(breakerStopwatch.ElapsedMilliseconds); breaker.Metrics.MarkCommandSuccess(); } else { breaker.Metrics.MarkCommandFailure(); } throw; } finally { command.ExecutionTimeMillis = executionStopwatch.Elapsed.TotalMilliseconds; if (success) { _metricEvents.BreakerSuccessCount(breaker.Name, command.Name); } else { _metricEvents.BreakerFailureCount(breaker.Name, command.Name); } } return(result); }