/// <summary>
        /// Builds a mutable bulkhead isolation <see cref="Policy{TResult}" />, 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 MutableBulkhead 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">onBulkheadRejected</exception>
        public static MutableBulkheadPolicy <TResult> Create <TResult>(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));
            }

            SemaphoreSlimDynamic maxParallelizationSemaphore = new SemaphoreSlimDynamic(0, maxParallelization, int.MaxValue);

            var maxQueuingCompounded = maxQueuingActions <= int.MaxValue - maxParallelization
                ? maxQueuingActions + maxParallelization
                : int.MaxValue;
            SemaphoreSlimDynamic maxQueuedActionsSemaphore = new SemaphoreSlimDynamic(0, maxQueuingCompounded, int.MaxValue);

            return(new MutableBulkheadPolicy <TResult>(
                       maxParallelization,
                       maxQueuingActions,
                       maxParallelizationSemaphore,
                       maxQueuedActionsSemaphore,
                       onBulkheadRejected
                       ));
        }
        internal static async Task <TResult> ImplementationAsync <TResult>(
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            Func <Context, Task> onBulkheadRejectedAsync,
            SemaphoreSlimDynamic maxParallelizationSemaphore,
            SemaphoreSlimDynamic 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(context, cancellationToken).ConfigureAwait(continueOnCapturedContext));
                }
                finally
                {
                    maxParallelizationSemaphore.Release();
                }
            }
            finally
            {
                maxQueuedActionsSemaphore.Release();
            }
        }
        internal static TResult Implementation <TResult>(
            Func <Context, CancellationToken, TResult> action,
            Context context,
            Action <Context> onBulkheadRejected,
            SemaphoreSlimDynamic maxParallelizationSemaphore,
            SemaphoreSlimDynamic maxQueuedActionsSemaphore,
            CancellationToken cancellationToken)
        {
            if (!maxQueuedActionsSemaphore.Wait(TimeSpan.Zero, cancellationToken))
            {
                onBulkheadRejected(context);
                throw new BulkheadRejectedException();
            }

            try
            {
                maxParallelizationSemaphore.Wait(cancellationToken);
                try
                {
                    return(action(context, cancellationToken));
                }
                finally
                {
                    maxParallelizationSemaphore.Release();
                }
            }
            finally
            {
                maxQueuedActionsSemaphore.Release();
            }
        }
 internal MutableBulkheadPolicy(
     int maxParallelization,
     int maxQueueingActions,
     SemaphoreSlimDynamic maxParallelizationSemaphore,
     SemaphoreSlimDynamic maxQueuedActionsSemaphore,
     Action <Context> onBulkheadRejected)
 {
     _maxParallelization          = maxParallelization;
     _maxQueuedActions            = maxQueueingActions;
     _maxParallelizationSemaphore = maxParallelizationSemaphore ?? throw new ArgumentNullException(nameof(maxParallelizationSemaphore));
     _maxQueuedActionsSemaphore   = maxQueuedActionsSemaphore ?? throw new ArgumentNullException(nameof(maxQueuedActionsSemaphore));
     _onBulkheadRejected          = onBulkheadRejected ?? throw new ArgumentNullException(nameof(onBulkheadRejected));
 }
 internal AsyncMutableBulkheadPolicy(
     int maxParallelization,
     int maxQueueingActions,
     SemaphoreSlimDynamic maxParallelizationSemaphore,
     SemaphoreSlimDynamic maxQueuedActionsSemaphore,
     Func <Context, Task> onBulkheadRejectedAsync)
 {
     _maxParallelization          = maxParallelization;
     _maxQueuedActions            = maxQueueingActions;
     _maxParallelizationSemaphore = maxParallelizationSemaphore;
     _maxQueuedActionsSemaphore   = maxQueuedActionsSemaphore;
     _onBulkheadRejectedAsync     = onBulkheadRejectedAsync ?? throw new ArgumentNullException(nameof(onBulkheadRejectedAsync));
 }