/// <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 )); }