public async Task InvokeAsync(CancellationToken cancellationToken = default) { // Build wrapped operation ActionOperation wrappedOperation = ExecuteAction; foreach (var circuitBreakerHandler in CircuitBreakerHandlers) { wrappedOperation = circuitBreakerHandler(wrappedOperation); } var totalInfo = new ResilientOperationTotalInfo(); var partiallyAppliedHandlers = new List <Func <Exception, Task <HandlerResult> > >(); // Prepare handlers foreach (var handler in Handlers) { var op = new ResilientOperation(ImplicitOperationKey, new ResilientOperationHandlerInfo(), totalInfo, cancellationToken); partiallyAppliedHandlers.Add((ex) => handler(op, ex)); } do { try { await wrappedOperation(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { try { await ProcessHandlers(partiallyAppliedHandlers, ex, cancellationToken); } catch (CircuitBrokenException circuitBrokenEx) { await ProcessHandlers(partiallyAppliedHandlers, circuitBrokenEx, cancellationToken); } } }while (true); }
public async Task <TResult> InvokeAsync(CancellationToken cancellationToken = default) { // Build wrapped operation Func <CancellationToken, Task <TResult> > wrappedOperation = ExecuteFunc; foreach (var circuitBreakerHandler in CircuitBreakerHandlers) { wrappedOperation = circuitBreakerHandler(wrappedOperation); } var totalInfo = new ResilientOperationTotalInfo(); var partiallyAppliedResultHandlers = new List <Func <TResult, Task <ResilientOperation <TResult> > > >(); // Prepare handlers foreach (var handler in ResultHandlers) { var op = new ResilientOperation <TResult>(ImplicitOperationKey, new ResilientOperationHandlerInfo(), totalInfo, cancellationToken); partiallyAppliedResultHandlers.Add(result => handler(op, result)); } var partiallyAppliedHandlers = new List <Func <Exception, Task <ResilientOperation <TResult> > > >(); // Prepare handlers foreach (var handler in Handlers) { var op = new ResilientOperation <TResult>(ImplicitOperationKey, new ResilientOperationHandlerInfo(), totalInfo, cancellationToken); partiallyAppliedHandlers.Add((ex) => handler(op, ex)); } do { try { var result = await wrappedOperation(cancellationToken).ConfigureAwait(false); ResilientOperation <TResult> op = null; foreach (var handler in partiallyAppliedResultHandlers) { op = await handler(result).ConfigureAwait(false); if (op.HandlerResult == HandlerResult.Unhandled) { continue; } else if (op.HandlerResult == HandlerResult.Retry) { break; } else if (op.HandlerResult == HandlerResult.Break) { return(result); } else if (op.HandlerResult == HandlerResult.Return) { return(op.Result); } } if (op?.HandlerResult == HandlerResult.Retry) { cancellationToken.ThrowIfCancellationRequested(); continue; } return(result); } catch (Exception ex) when(!(ex is OperationCanceledException)) { var exToHandle = ex; ResilientOperation <TResult> op = null; do { try { foreach (var handler in partiallyAppliedHandlers) { op = await handler(exToHandle).ConfigureAwait(false); if (op.HandlerResult == HandlerResult.Unhandled) { continue; } else if (op.HandlerResult == HandlerResult.Retry) { break; } else if (op.HandlerResult == HandlerResult.Break) { break; } else if (op.HandlerResult == HandlerResult.Return) { return(op.Result); } } if (op?.HandlerResult == HandlerResult.Retry) { break; } ExceptionDispatchInfo.Capture(exToHandle).Throw(); } catch (Exception handlerEx) when(handlerEx != exToHandle && !(handlerEx is OperationCanceledException)) { exToHandle = handlerEx; continue; } }while (true); continue; } }while (true); }