/// <summary> /// Create a <see cref="ResilientFuncBuilder{TFunction, TResult}"/> from an existing synchronous function. /// </summary> /// <param name="function">A synchronous function that is not already resilient.</param> /// <returns>A new builder for the operation to configure resiliency.</returns> public static ResilientFuncBuilder <Func <TResult>, TResult> AsResilient <TResult>( this Func <TResult> function, [CallerLineNumber] int sourceLineNumber = 0, [CallerFilePath] string sourceFilePath = "", [CallerMemberName] string memberName = "") { return(ResilientOperation.From(function, sourceLineNumber, sourceFilePath, memberName)); }
/// <summary> /// Create a <see cref="ResilientActionBuilder{TAction}"/> from an existing synchronous action. /// </summary> /// <param name="action">A synchronous action that is not already resilient.</param> /// <returns>A new builder for the operation to configure resiliency.</returns> public static ResilientActionBuilder <Action> AsResilient( this Action action, [CallerLineNumber] int sourceLineNumber = 0, [CallerFilePath] string sourceFilePath = "", [CallerMemberName] string memberName = "") { return(ResilientOperation.From(action, sourceLineNumber, sourceFilePath, memberName)); }
/// <summary> /// Create a <see cref="ResilientActionBuilder{TAction}"/> from an existing async action with cancellation support. /// </summary> /// <param name="action">An async action, that supports cancellation, that is not already resilient.</param> /// <returns>A new builder for the operation to configure resiliency.</returns> public static ResilientActionBuilder <Func <CancellationToken, Task> > AsResilient( this Func <CancellationToken, Task> action, [CallerLineNumber] int sourceLineNumber = 0, [CallerFilePath] string sourceFilePath = "", [CallerMemberName] string memberName = "") { return(ResilientOperation.From(action, sourceLineNumber, sourceFilePath, memberName)); }
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); }
public static Task WaitAsync(this ResilientOperation op, TimeSpan period) => ResilientOperation.WaiterFactory(op.CancellationToken).WaitAsync(period);
public static async Task WaitThenRetryAsync(this ResilientOperation op, TimeSpan period) { await op.WaitAsync(period).ConfigureAwait(false); op.Retry(); }