Ejemplo n.º 1
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  operationKey           = "SomeKey";
            Context contextPassedToExecute = new Context(operationKey);

            Context          contextPassedToOnRejected = null;
            Action <Context> onRejected = ctx => { contextPassedToOnRejected = ctx; };

            MutableBulkheadPolicy <int> MutableBulkhead = MutableBulkheadPolicy
                                                          .Create <int>(1, onRejected);

            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();

            using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
            {
                Task.Run(() => {
                    MutableBulkhead.Execute(() =>
                    {
                        tcs.Task.Wait();
                        return(0);
                    });
                });

                Within(shimTimeSpan, () => MutableBulkhead.BulkheadAvailableCount.Should().Be(0)); // Time for the other thread to kick up and take the MutableBulkhead.

                MutableBulkhead.Invoking(b => b.Execute(ctx => 1, contextPassedToExecute)).ShouldThrow <BulkheadRejectedException>();

                cancellationSource.Cancel();
                tcs.SetCanceled();
            }

            contextPassedToOnRejected.Should().NotBeNull();
            contextPassedToOnRejected.OperationKey.Should().Be(operationKey);
            contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
        }
Ejemplo n.º 2
0
        // Note re TaskCreationOptions.LongRunning: Testing the parallelization of the bulkhead policy efficiently requires the ability to start large numbers of parallel tasks in a short space of time.  The ThreadPool's algorithm of only injecting extra threads (when necessary) at a rate of two-per-second however makes high-volume tests using the ThreadPool both slow and flaky.  For PCL tests further, ThreadPool.SetMinThreads(...) is not available, to mitigate this.  Using TaskCreationOptions.LongRunning allows us to force tasks to be started near-instantly on non-ThreadPool threads.
        // Similarly, we use ConfigureAwait(true) when awaiting, to avoid continuations being scheduled onto a ThreadPool thread, which may only be injected too slowly in high-volume tests.

        public Task ExecuteOnBulkhead(MutableBulkheadPolicy bulkhead)
        {
            if (Status != TraceableActionStatus.Unstarted)
            {
                throw new InvalidOperationException(_id + "Action has previously been started.");
            }
            Status = TraceableActionStatus.StartRequested;

            return(Task.Factory.StartNew(() =>
            {
                try
                {
                    Status = TraceableActionStatus.QueueingForSemaphore;

                    bulkhead.Execute(ct =>
                    {
                        Status = TraceableActionStatus.Executing;

                        _tcsProxyForRealWork.Task.ContinueWith(CaptureCompletion()).Wait();

                        _testOutputHelper.WriteLine(_id + "Exiting execution.");
                    }, CancellationSource.Token);
                }
                catch (BulkheadRejectedException)
                {
                    Status = TraceableActionStatus.Rejected;
                }
                catch (OperationCanceledException)
                {
                    if (Status != TraceableActionStatus.Canceled)
                    {
                        _testOutputHelper.WriteLine(_id + "Caught queue cancellation.");
                        Status = TraceableActionStatus.Canceled;
                    } // else: was execution cancellation rethrown: ignore
                }
                catch (AggregateException ae)
                {
                    if (ae.InnerExceptions.Count == 1 && ae.InnerException is OperationCanceledException)
                    {
                        if (Status != TraceableActionStatus.Canceled)
                        {
                            _testOutputHelper.WriteLine(_id + "Caught queue cancellation.");
                            Status = TraceableActionStatus.Canceled;
                        } // else: was execution cancellation rethrown: ignore
                    }
                    else
                    {
                        throw;
                    }
                }
                catch (Exception e)
                {
                    _testOutputHelper.WriteLine(_id + "Caught unexpected exception during execution: " + e);

                    Status = TraceableActionStatus.Faulted;
                }
            },
                                         TaskCreationOptions.LongRunning));
        }