internal static TResult Implementation <TResult>( Func <CancellationToken, TResult> action, Context context, Action <Context> onBulkheadRejected, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore, CancellationToken cancellationToken) { if (!maxQueuedActionsSemaphore.Wait(TimeSpan.Zero, cancellationToken)) { onBulkheadRejected(context); throw new BulkheadRejectedException(); } try { maxParallelizationSemaphore.Wait(cancellationToken); try { return(action(cancellationToken)); } finally { maxParallelizationSemaphore.Release(); } } finally { maxQueuedActionsSemaphore.Release(); } }
internal static async Task <TResult> ImplementationAsync <TResult>( Func <CancellationToken, Task <TResult> > action, Context context, Func <Context, Task> onBulkheadRejectedAsync, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore, CancellationToken cancellationToken, bool continueOnCapturedContext) { if (!await maxQueuedActionsSemaphore.WaitAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(continueOnCapturedContext)) { await onBulkheadRejectedAsync(context).ConfigureAwait(continueOnCapturedContext); throw new BulkheadRejectedException(); } try { await maxParallelizationSemaphore.WaitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext); try { return(await action(cancellationToken).ConfigureAwait(continueOnCapturedContext)); } finally { maxParallelizationSemaphore.Release(); } } finally { maxQueuedActionsSemaphore.Release(); } }
internal BulkheadPolicy(Func <Func <Context, CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy, int maxParallelization, int maxQueueingActions, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore) : base(asyncExceptionPolicy, PredicateHelper.EmptyExceptionPredicates) { _maxParallelization = maxParallelization; _maxQueueingActions = maxQueueingActions; _maxParallelizationSemaphore = maxParallelizationSemaphore; _maxQueuedActionsSemaphore = maxQueuedActionsSemaphore; }
internal BulkheadPolicy(Func<Func<CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy, int maxParallelization, int maxQueueingActions, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore) : base(asyncExceptionPolicy, PredicateHelper.EmptyExceptionPredicates) { _maxParallelization = maxParallelization; _maxQueueingActions = maxQueueingActions; _maxParallelizationSemaphore = maxParallelizationSemaphore; _maxQueuedActionsSemaphore = maxQueuedActionsSemaphore; }
internal BulkheadPolicy( Action <Action <CancellationToken>, Context, CancellationToken> exceptionPolicy, int maxParallelization, int maxQueueingActions, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore ) : base(exceptionPolicy, PredicateHelper.EmptyExceptionPredicates) { _maxParallelization = maxParallelization; _maxQueueingActions = maxQueueingActions; _maxParallelizationSemaphore = maxParallelizationSemaphore; _maxQueuedActionsSemaphore = maxQueuedActionsSemaphore; }
internal BulkheadPolicy( Action<Action<CancellationToken>, Context, CancellationToken> exceptionPolicy, int maxParallelization, int maxQueueingActions, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore ) : base(exceptionPolicy, PredicateHelper.EmptyExceptionPredicates) { _maxParallelization = maxParallelization; _maxQueueingActions = maxQueueingActions; _maxParallelizationSemaphore = maxParallelizationSemaphore; _maxQueuedActionsSemaphore = maxQueuedActionsSemaphore; }
/// <summary> /// Builds a bulkhead isolation <see cref="Policy" />, which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. /// <para>When an execution would cause the number of actions executing concurrently through the policy to exceed <paramref name="maxParallelization" />, the policy allows a further <paramref name="maxQueuingActions" /> executions to queue, waiting for a concurrent execution slot. When an execution would cause the number of queuing actions to exceed <paramref name="maxQueuingActions" />, a <see cref="BulkheadRejectedException" /> is thrown.</para> /// </summary> /// <param name="maxParallelization">The maximum number of concurrent actions that may be executing through the policy.</param> /// <param name="maxQueuingActions">The maximum number of actions that may be queuing, waiting for an execution slot.</param> /// <param name="onBulkheadRejectedAsync">An action to call asynchronously, if the bulkhead rejects execution due to oversubscription.</param> /// <returns>The policy instance.</returns> /// <exception cref="System.ArgumentOutOfRangeException">maxParallelization;Value must be greater than zero.</exception> /// <exception cref="System.ArgumentOutOfRangeException">maxQueuingActions;Value must be greater than or equal to zero.</exception> /// <exception cref="System.ArgumentNullException">onBulkheadRejectedAsync</exception> public static BulkheadPolicy BulkheadAsync(int maxParallelization, int maxQueuingActions, Func <Context, Task> onBulkheadRejectedAsync) { if (maxParallelization <= 0) { throw new ArgumentOutOfRangeException(nameof(maxParallelization), "Value must be greater than zero."); } if (maxQueuingActions < 0) { throw new ArgumentOutOfRangeException(nameof(maxQueuingActions), "Value must be greater than or equal to zero."); } if (onBulkheadRejectedAsync == null) { throw new ArgumentNullException(nameof(onBulkheadRejectedAsync)); } SemaphoreSlim maxParallelizationSemaphore = SemaphoreSlimFactory.CreateSemaphoreSlim(maxParallelization); var maxQueuingCompounded = maxQueuingActions <= int.MaxValue - maxParallelization ? maxQueuingActions + maxParallelization : int.MaxValue; SemaphoreSlim maxQueuedActionsSemaphore = SemaphoreSlimFactory.CreateSemaphoreSlim(maxQueuingCompounded); return(new BulkheadPolicy((action, context, cancellationToken, continueOnCapturedContext) => BulkheadEngine.ImplementationAsync( async(ctx, ct) => { await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; }, context, onBulkheadRejectedAsync, maxParallelizationSemaphore, maxQueuedActionsSemaphore, cancellationToken, continueOnCapturedContext), maxParallelization, maxQueuingActions, maxParallelizationSemaphore, maxQueuedActionsSemaphore )); }
/// <summary> /// Builds a bulkhead isolation <see cref="Policy" />, which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. /// <para>When an execution would cause the number of actions executing concurrently through the policy to exceed <paramref name="maxParallelization" />, the policy allows a further <paramref name="maxQueuingActions" /> executions to queue, waiting for a concurrent execution slot. When an execution would cause the number of queuing actions to exceed <paramref name="maxQueuingActions" />, a <see cref="BulkheadRejectedException" /> is thrown.</para> /// </summary> /// <param name="maxParallelization">The maximum number of concurrent actions that may be executing through the policy.</param> /// <param name="maxQueuingActions">The maxmimum number of actions that may be queuing, waiting for an execution slot.</param> /// <param name="onBulkheadRejected">An action to call, if the bulkhead rejects execution due to oversubscription.</param> /// <returns>The policy instance.</returns> /// <exception cref="System.ArgumentOutOfRangeException">maxParallelization;Value must be greater than zero.</exception> /// <exception cref="System.ArgumentOutOfRangeException">maxParallelization;Value must be greater than zero.</exception> /// <exception cref="System.ArgumentNullException">onBulkheadRejected</exception> public static BulkheadPolicy Bulkhead(int maxParallelization, int maxQueuingActions, Action <Context> onBulkheadRejected) { if (maxParallelization <= 0) { throw new ArgumentOutOfRangeException(nameof(maxParallelization), "Value must be greater than zero."); } if (maxQueuingActions < 0) { throw new ArgumentOutOfRangeException(nameof(maxQueuingActions), "Value must be greater than or equal to zero."); } if (onBulkheadRejected == null) { throw new ArgumentNullException(nameof(onBulkheadRejected)); } SemaphoreSlim maxParallelizationSemaphore = SemaphoreSlimFactory.CreateSemaphoreSlim(maxParallelization); var maxQueuingCompounded = maxQueuingActions <= int.MaxValue - maxParallelization ? maxQueuingActions + maxParallelization : int.MaxValue; SemaphoreSlim maxQueuedActionsSemaphore = SemaphoreSlimFactory.CreateSemaphoreSlim(maxQueuingCompounded); return(new BulkheadPolicy( (action, context, cancellationToken) => BulkheadEngine.Implementation( ct => { action(ct); return EmptyStruct.Instance; }, context, onBulkheadRejected, maxParallelizationSemaphore, maxQueuedActionsSemaphore, cancellationToken ), maxParallelization, maxQueuingActions, maxParallelizationSemaphore, maxQueuedActionsSemaphore )); }