Esempio n. 1
0
        public void Should_control_executions_queuing_and_rejections_per_specification_with_cancellations(
            int maxParallelization, int maxQueuingActions, int totalActions, bool cancelQueuing,
            bool cancelExecuting, string scenario)
        {
            if (totalActions < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(totalActions));
            }
            scenario = String.Format("MaxParallelization {0}; MaxQueuing {1}; TotalActions {2}; CancelQueuing {3}; CancelExecuting {4}: {5}", maxParallelization, maxQueuingActions, totalActions, cancelQueuing, cancelExecuting, scenario);

            BulkheadPolicy <ResultPrimitive> bulkhead = Policy.Bulkhead <ResultPrimitive>(maxParallelization, maxQueuingActions);

            // Set up delegates which we can track whether they've started; and control when we allow them to complete (to release their semaphore slot).
            actions = new TraceableAction[totalActions];
            for (int i = 0; i < totalActions; i++)
            {
                actions[i] = new TraceableAction(i, statusChanged, testOutputHelper);
            }

            // Throw all the delegates at the bulkhead simultaneously.
            Task[] tasks = new Task[totalActions];
            for (int i = 0; i < totalActions; i++)
            {
                tasks[i] = actions[i].ExecuteOnBulkhead(bulkhead);
            }

            testOutputHelper.WriteLine("Immediately after queueing...");
            testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
            testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
            OutputActionStatuses();

            // Assert the expected distributions of executing, queuing, rejected and completed - when all delegates thrown at bulkhead.
            int expectedCompleted    = 0;
            int expectedCancelled    = 0;
            int expectedExecuting    = Math.Min(totalActions, maxParallelization);
            int expectedRejects      = Math.Max(0, totalActions - maxParallelization - maxQueuingActions);
            int expectedQueuing      = Math.Min(maxQueuingActions, Math.Max(0, totalActions - maxParallelization));
            int expectedBulkheadFree = maxParallelization - expectedExecuting;
            int expectedQueueFree    = maxQueuingActions - expectedQueuing;

            try
            {
                actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, scenario + ", when checking expectedExecuting"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, scenario + ", when checking expectedQueuing"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, scenario + ", when checking expectedRejects"));
                actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, scenario + ", when checking expectedCompleted");
                actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, scenario + ", when checking expectedCancelled");
                Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, scenario + ", when checking expectedBulkheadFree"));
                Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, scenario + ", when checking expectedQueueFree"));
            }
            finally
            {
                testOutputHelper.WriteLine("Expected initial state verified...");
                testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                OutputActionStatuses();
            }

            // Complete or cancel delegates one by one, and expect others to take their place (if a slot released and others remain queueing); until all work is done.
            while (expectedExecuting > 0)
            {
                if (cancelQueuing)
                {
                    testOutputHelper.WriteLine("Cancelling a queueing task...");

                    actions.First(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Cancel();

                    expectedCancelled++;
                    expectedQueuing--;
                    expectedQueueFree++;

                    cancelQueuing = false;
                }
                else if (cancelExecuting)
                {
                    testOutputHelper.WriteLine("Cancelling an executing task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).Cancel();

                    expectedCancelled++;
                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }

                    cancelExecuting = false;
                }
                else // Complete an executing delegate.
                {
                    testOutputHelper.WriteLine("Completing a task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).AllowCompletion();

                    expectedCompleted++;

                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }
                }
                try
                {
                    actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, scenario + ", when checking expectedExecuting"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, scenario + ", when checking expectedQueuing"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, scenario + ", when checking expectedCompleted"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, scenario + ", when checking expectedCancelled"));
                    actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, scenario + ", when checking expectedRejects");
                    Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, scenario + ", when checking expectedBulkheadFree"));
                    Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, scenario + ", when checking expectedQueueFree"));
                }
                finally
                {
                    testOutputHelper.WriteLine("End of next loop iteration...");
                    testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                    testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                    OutputActionStatuses();
                }
            }

            EnsureNoUnbservedTaskExceptions(tasks);
            testOutputHelper.WriteLine("Verifying all tasks completed...");
            Within(shimTimeSpan, () => tasks.All(t => t.IsCompleted).Should().BeTrue());

            #endregion
        }
        public void Should_control_executions_queuing_and_rejections_per_specification_with_cancellations(
            int maxParallelization, int maxQueuingActions, int totalActions, string because, bool cancelQueuing,
            bool cancelExecuting)
        {
            if (totalActions < 0) throw new ArgumentOutOfRangeException(nameof(totalActions));
            because = String.Format("MaxParallelization {0}; MaxQueuing {1}; TotalActions {2}; CancelQueuing {3}; CancelExecuting {4}: {5}", maxParallelization, maxQueuingActions, totalActions, cancelQueuing, cancelExecuting, because);

            BulkheadPolicy<ResultPrimitive> bulkhead = Policy.BulkheadAsync<ResultPrimitive>(maxParallelization, maxQueuingActions);

            // Set up delegates which we can track whether they've started; and control when we allow them to complete (to release their semaphore slot).
            actions = new TraceableAction[totalActions];
            for (int i = 0; i < totalActions; i++) { actions[i] = new TraceableAction(i, statusChanged, testOutputHelper); }

            // Throw all the delegates at the bulkhead simultaneously.
            Task<ResultPrimitive>[] tasks = new Task<ResultPrimitive>[totalActions];
            for (int i = 0; i < totalActions; i++) { tasks[i] = actions[i].ExecuteOnBulkheadAsync<ResultPrimitive>(bulkhead); }

            testOutputHelper.WriteLine("Immediately after queueing...");
            testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
            testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
            OutputActionStatuses();

            // Assert the expected distributions of executing, queuing, rejected and completed - when all delegates thrown at bulkhead.
            int expectedCompleted = 0;
            int expectedCancelled = 0;
            int expectedExecuting = Math.Min(totalActions, maxParallelization);
            int expectedRejects = Math.Max(0, totalActions - maxParallelization - maxQueuingActions);
            int expectedQueuing = Math.Min(maxQueuingActions, Math.Max(0, totalActions - maxParallelization));
            int expectedBulkheadFree = maxParallelization - expectedExecuting;
            int expectedQueueFree = maxQueuingActions - expectedQueuing;

            try
            {
                actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, because + ", when checking expectedExecuting"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, because + ", when checking expectedQueuing"));
                Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, because + ", when checking expectedRejects"));
                actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, because + ", when checking expectedCompleted");
                actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, because + ", when checking expectedCancelled");
                Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, because + ", when checking expectedBulkheadFree"));
                Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, because + ", when checking expectedQueueFree"));
            }
            finally
            {
                testOutputHelper.WriteLine("Expected initial state verified...");
                testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                OutputActionStatuses();
            }

            // Complete or cancel delegates one by one, and expect others to take their place (if a slot released and others remain queueing); until all work is done.
            while (expectedExecuting > 0)
            {
                if (cancelQueuing)
                {
                    testOutputHelper.WriteLine("Cancelling a queueing task...");

                    actions.First(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Cancel();

                    expectedCancelled++;
                    expectedQueuing--;
                    expectedQueueFree++;

                    cancelQueuing = false;
                }
                else if (cancelExecuting)
                {
                    testOutputHelper.WriteLine("Cancelling an executing task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).Cancel();

                    expectedCancelled++;
                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }

                    cancelExecuting = false;
                }
                else // Complete an executing delegate.
                {
                    testOutputHelper.WriteLine("Completing a task...");

                    actions.First(a => a.Status == TraceableActionStatus.Executing).AllowCompletion();

                    expectedCompleted++;

                    if (expectedQueuing > 0)
                    {
                        expectedQueuing--;
                        expectedQueueFree++;
                    }
                    else
                    {
                        expectedExecuting--;
                        expectedBulkheadFree++;
                    }

                }

                try
                {
                    actions.Count(a => a.Status == TraceableActionStatus.Faulted).Should().Be(0);
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Executing).Should().Be(expectedExecuting, because + ", when checking expectedExecuting"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Should().Be(expectedQueuing, because + ", when checking expectedQueuing"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Completed).Should().Be(expectedCompleted, because + ", when checking expectedCompleted"));
                    Within(shimTimeSpan, () => actions.Count(a => a.Status == TraceableActionStatus.Canceled).Should().Be(expectedCancelled, because + ", when checking expectedCancelled"));
                    actions.Count(a => a.Status == TraceableActionStatus.Rejected).Should().Be(expectedRejects, because + ", when checking expectedRejects");
                    Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(expectedBulkheadFree, because + ", when checking expectedBulkheadFree"));
                    Within(shimTimeSpan, () => bulkhead.QueueAvailableCount.Should().Be(expectedQueueFree, because + ", when checking expectedQueueFree"));
                }
                finally
                {
                    testOutputHelper.WriteLine("End of next loop iteration...");
                    testOutputHelper.WriteLine("Bulkhead: {0} slots out of {1} available.", bulkhead.BulkheadAvailableCount, maxParallelization);
                    testOutputHelper.WriteLine("Bulkhead queue: {0} slots out of {1} available.", bulkhead.QueueAvailableCount, maxQueuingActions);
                    OutputActionStatuses();
                }
            }

            EnsureNoUnbservedTaskExceptions(tasks); 
            testOutputHelper.WriteLine("Verifying all tasks completed...");
            Within(shimTimeSpan, () => tasks.All(t => t.IsCompleted).Should().BeTrue());
        }
Esempio n. 3
0
        public void Should_control_executions_per_specification(int maxParallelization, int maxQueuingActions, int totalActions, bool cancelQueuing, bool cancelExecuting, string scenario)
        {
            if (totalActions < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(totalActions));
            }

            MaxParallelization = maxParallelization;
            MaxQueuingActions  = maxQueuingActions;
            TotalActions       = totalActions;
            Scenario           = $"MaxParallelization {maxParallelization}; MaxQueuing {maxQueuingActions}; TotalActions {totalActions}; CancelQueuing {cancelQueuing}; CancelExecuting {cancelExecuting}: {scenario}";

            IBulkheadPolicy bulkhead = GetBulkhead(maxParallelization, maxQueuingActions);

            using (bulkhead)
            {
                BulkheadForStats = bulkhead;

                // Set up delegates which we can track whether they've started; and control when we allow them to complete (to release their semaphore slot).
                Actions = new TraceableAction[totalActions];
                for (int i = 0; i < totalActions; i++)
                {
                    Actions[i] = new TraceableAction(i, StatusChangedEvent, TestOutputHelper);
                }

                // Throw all the delegates at the bulkhead simultaneously.
                Tasks = new Task[totalActions];
                for (int i = 0; i < totalActions; i++)
                {
                    Tasks[i] = ExecuteOnBulkhead(bulkhead, Actions[i]);
                }

                OutputStatus("Immediately after queueing...");

                // Assert the expected distributions of executing, queuing, rejected and completed - when all delegates thrown at bulkhead.
                ExpectedCompleted    = 0;
                ExpectedCancelled    = 0;
                ExpectedExecuting    = Math.Min(totalActions, maxParallelization);
                ExpectedRejects      = Math.Max(0, totalActions - maxParallelization - maxQueuingActions);
                ExpectedQueuing      = Math.Min(maxQueuingActions, Math.Max(0, totalActions - maxParallelization));
                ExpectedBulkheadFree = maxParallelization - ExpectedExecuting;
                ExpectedQueueFree    = maxQueuingActions - ExpectedQueuing;

                try
                {
                    Within(CohesionTimeLimit, ActualsMatchExpecteds);
                }
                finally
                {
                    OutputStatus("Expected initial state verified...");
                }

                // Complete or cancel delegates one by one, and expect others to take their place (if a slot released and others remain queueing); until all work is done.
                while (ExpectedExecuting > 0)
                {
                    if (cancelQueuing)
                    {
                        TestOutputHelper.WriteLine("Cancelling a queueing task...");

                        Actions.First(a => a.Status == TraceableActionStatus.QueueingForSemaphore).Cancel();

                        ExpectedCancelled++;
                        ExpectedQueuing--;
                        ExpectedQueueFree++;

                        cancelQueuing = false;
                    }
                    else if (cancelExecuting)
                    {
                        TestOutputHelper.WriteLine("Cancelling an executing task...");

                        Actions.First(a => a.Status == TraceableActionStatus.Executing).Cancel();

                        ExpectedCancelled++;
                        if (ExpectedQueuing > 0)
                        {
                            ExpectedQueuing--;
                            ExpectedQueueFree++;
                        }
                        else
                        {
                            ExpectedExecuting--;
                            ExpectedBulkheadFree++;
                        }

                        cancelExecuting = false;
                    }
                    else // Complete an executing delegate.
                    {
                        TestOutputHelper.WriteLine("Completing a task...");

                        Actions.First(a => a.Status == TraceableActionStatus.Executing).AllowCompletion();

                        ExpectedCompleted++;

                        if (ExpectedQueuing > 0)
                        {
                            ExpectedQueuing--;
                            ExpectedQueueFree++;
                        }
                        else
                        {
                            ExpectedExecuting--;
                            ExpectedBulkheadFree++;
                        }
                    }

                    try
                    {
                        Within(CohesionTimeLimit, ActualsMatchExpecteds);
                    }
                    finally
                    {
                        OutputStatus("End of next loop iteration...");
                    }
                }

                EnsureNoUnbservedTaskExceptions();

                TestOutputHelper.WriteLine("Verifying all tasks completed...");
                Within(CohesionTimeLimit, AllTasksCompleted);
            }
        }
Esempio n. 4
0
 protected abstract Task ExecuteOnBulkhead(IBulkheadPolicy bulkhead, TraceableAction action);
Esempio n. 5
0
 protected override Task ExecuteOnBulkhead(IBulkheadPolicy bulkhead, TraceableAction action)
 {
     return(action.ExecuteOnBulkhead <ResultPrimitive>((BulkheadPolicy <ResultPrimitive>)bulkhead));
 }
 protected override Task ExecuteOnBulkhead(IBulkheadPolicy bulkhead, TraceableAction action)
 {
     return(action.ExecuteOnBulkheadAsync((AsyncBulkheadPolicy)bulkhead));
 }