/// <summary> /// see RepeatTemplate#WaitForResults /// </summary> /// <param name="state"></param> /// <returns></returns> protected override bool WaitForResults(IRepeatInternalState state) { IResultQueue <IResultHolder> queue = ((ResultQueueInternalState)state).ResultQueue; bool result = true; while (queue.IsExpecting()) { // Careful that no runnables that are not going to finish ever get // onto the queue, else this may block forever. IResultHolder future; try { future = queue.Take(); } catch (ThreadInterruptedException) { Thread.CurrentThread.Interrupt(); throw new RepeatException("InterruptedException while waiting for result."); } if (future.Error != null) { state.GetExceptions().Add(future.Error); result = false; } else { RepeatStatus status = future.Result; result = result && CanContinue(status); ExecuteAfterInterceptors(future.Context, status); } } Assert.State(queue.IsEmpty(), "Future results queue should be empty at end of batch."); return(result); }
/// <summary> /// see RepeatTemplate#WaitForResults /// </summary> /// <param name="state"></param> /// <returns></returns> protected override bool WaitForResults(IRepeatInternalState state) { IResultQueue<IResultHolder> queue = ((ResultQueueInternalState)state).ResultQueue; bool result = true; while (queue.IsExpecting()) { // Careful that no runnables that are not going to finish ever get // onto the queue, else this may block forever. IResultHolder future; try { future = queue.Take(); } catch (ThreadInterruptedException) { Thread.CurrentThread.Interrupt(); throw new RepeatException("InterruptedException while waiting for result."); } if (future.Error != null) { state.GetExceptions().Add(future.Error); result = false; } else { RepeatStatus status = future.Result; result = result && CanContinue(status); ExecuteAfterInterceptors(future.Context, status); } } Assert.State(queue.IsEmpty(), "Future results queue should be empty at end of batch."); return result; }
/// <summary> /// /// </summary> /// <param name="callback"></param> /// <returns></returns> private RepeatStatus ExecuteInternal(RepeatCallback callback) { // Reset the termination policy if there is one... IRepeatContext context = Start(); // Make sure if we are already marked complete before we start then no // processing takes place. bool running = !IsMarkedComplete(context); foreach (IRepeatListener interceptor in _listeners) { interceptor.Open(context); running = running && !IsMarkedComplete(context); if (!running) { break; } } // Return value, default is to allow continued processing. RepeatStatus result = RepeatStatus.Continuable; IRepeatInternalState state = CreateInternalState(context); // This is the list of exceptions thrown by all active callbacks ICollection <System.Exception> exceptions = state.GetExceptions(); // Keep a separate list of exceptions we handled that need to be // rethrown ICollection <System.Exception> deferred = new List <System.Exception>(); try { while (running) { #region WhileRunning /* * Run the before interceptors here, not in the task executor so * that they all happen in the same thread - it's easier for * tracking batch status, amongst other things. */ foreach (IRepeatListener interceptor in _listeners) { interceptor.Before(context); // Allow before interceptors to veto the batch by setting // flag. running = running && !IsMarkedComplete(context); } // Check that we are still running (should always be true) ... if (running) { #region Running try { result = GetNextResult(context, callback, state); ExecuteAfterInterceptors(context, result); } catch (System.Exception exception) { DoHandle(exception, context, deferred); } // N.B. the order may be important here: if (IsComplete(context, result) || IsMarkedComplete(context) || deferred.Any()) { running = false; } #endregion } #endregion } result = result.And(WaitForResults(state)); foreach (System.Exception exception in exceptions) { DoHandle(exception, context, deferred); } // Explicitly drop any references to internal state... // useless ? state = null; } /* * No need for explicit catch here - if the business processing threw an * exception it was already handled by the helper methods. An exception * here is necessarily fatal. */ finally { #region HandleFinally HandleFinally(deferred, _listeners, context); #endregion } return(result); }