Ejemplo n.º 1
0
        private Action <Task <object> > CaptureCompletion() => t =>
        {
            if (t.IsCanceled)
            {
                _testOutputHelper.WriteLine(_id + "Cancelling execution.");

                Status = TraceableActionStatus.Canceled;
                throw new OperationCanceledException(CancellationSource.Token); // Exception rethrown for the purpose of testing exceptions thrown through the BulkheadEngine.
            }
            else if (t.IsFaulted)
            {
                _testOutputHelper.WriteLine(_id + "Execution faulted.");
                if (t.Exception != null)
                {
                    _testOutputHelper.WriteLine(_id + "Exception: " + t.Exception);
                }

                Status = TraceableActionStatus.Faulted;
            }
            else
            {
                _testOutputHelper.WriteLine(_id + "Completing execution.");

                Status = TraceableActionStatus.Completed;
            }
        };
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(BulkheadPolicy 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));
        }
Ejemplo n.º 3
0
        private void ExecuteThroughSyncBulkheadInner()
        {
            Status = TraceableActionStatus.Executing;

            _tcsProxyForRealWork.Task.ContinueWith(CaptureCompletion(), TaskContinuationOptions.ExecuteSynchronously).Wait();

            _testOutputHelper.WriteLine(_id + "Exiting execution.");
        }
Ejemplo n.º 4
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.
        private Task ExecuteThroughSyncBulkheadOuter(Action executeThroughBulkheadInner)
        {
            if (Status != TraceableActionStatus.Unstarted)
            {
                throw new InvalidOperationException(_id + "Action has previously been started.");
            }
            Status = TraceableActionStatus.StartRequested;

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

                    executeThroughBulkheadInner();
                }
                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;
                }
                finally
                {
                    // Exiting the execution successfully is also a change of state (on which assertions may be occurring) in that it releases a semaphore slot sucessfully.
                    // There can also be races between assertions and executions-responding-to-previous-state-changes, so a second signal presents another opportunity for assertions to be run.
                    SignalStateChange();
                }
            },
                                         TaskCreationOptions.LongRunning));
        }
Ejemplo n.º 5
0
        public Task <TResult> ExecuteOnBulkheadAsync <TResult>(BulkheadPolicy <TResult> bulkhead)
        {
            if (Status != TraceableActionStatus.Unstarted)
            {
                throw new InvalidOperationException(_id + "Action has previously been started.");
            }
            Status = TraceableActionStatus.StartRequested;

            TResult result = default(TResult);

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

                    result = await bulkhead.ExecuteAsync(async ct =>
                    {
                        Status = TraceableActionStatus.Executing;

                        await _tcsProxyForRealWork.Task.ContinueWith(CaptureCompletion()).ConfigureAwait(true);

                        _testOutputHelper.WriteLine(_id + "Exiting execution.");

                        return default(TResult);
                    }, CancellationSource.Token).ConfigureAwait(true);
                }
                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 (Exception e)
                {
                    _testOutputHelper.WriteLine(_id + "Caught unexpected exception during execution: " + e);

                    Status = TraceableActionStatus.Faulted;
                }
                return result;
            }
                                         , TaskCreationOptions.LongRunning).Unwrap());
        }