private async void StartWorkQueueProcessingAsync(IChannelHandlerContext context) { try { while (_backlogQueue.Any() && State != States.Aborted && _backlogQueue.TryDequeue(out TWork workItem)) { await DoWorkAsync(context, workItem).ConfigureAwait(false); } switch (State) { case States.Processing: State = States.Idle; break; case States.FinalProcessing: case States.Aborted: _completionSource.TrySetResult(); break; default: throw new ArgumentOutOfRangeException(nameof(State), "Unexpected state."); } } catch (Exception ex) { Abort(); _completionSource.TrySetException(new ChannelMessageProcessingException(ex, context)); } }
private static Task <ProcessOutput> CreateTaskAsync( Process process, TaskCompletionSource <ProcessOutput> taskCompletionSource, CancellationToken cancellationToken, Predicate <int> isErrorCodeOk = null, Action <string> onOutputDataReceived = null, Action <string> onErrorDataReceived = null) { cancellationToken.ThrowIfCancellationRequested(); if (taskCompletionSource == null) { throw new ArgumentNullException(nameof(taskCompletionSource)); } if (process == null) { return(taskCompletionSource.Task); } if (isErrorCodeOk == null) { isErrorCodeOk = exitCode => exitCode == 0; } var errorLines = new List <string>(); var outputLines = new List <string>(); process.OutputDataReceived += (s, e) => { if (e.Data != null) { outputLines.Add(e.Data); onOutputDataReceived?.Invoke(e.Data); } }; process.ErrorDataReceived += (s, e) => { if (e.Data != null) { errorLines.Add(e.Data); onErrorDataReceived?.Invoke(e.Data); } }; process.Exited += (s, e) => { var processOutput = new ProcessOutput(process.ExitCode, outputLines, errorLines); if (isErrorCodeOk?.Invoke(process.ExitCode) == true) { taskCompletionSource.TrySetResult(processOutput); } else { taskCompletionSource.TrySetException(new ProcessFailureException(process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, processOutput)); } }; var registration = cancellationToken.Register(() => { if (taskCompletionSource.TrySetCanceled()) { // If the underlying process is still running, we should kill it if (!process.HasExited) { try { process.Kill(); } catch (InvalidOperationException) { // Ignore, since the process is already dead } } } }); return(taskCompletionSource.Task); }
private static Task <TResult> CatchImplContinuation <TResult>(Task task, Func <Task <TResult> > continuation) { SynchronizationContext syncContext = SynchronizationContext.Current; TaskCompletionSource <Task <TResult> > tcs = new TaskCompletionSource <Task <TResult> >(); // this runs only if the inner task did not fault task.ContinueWith(innerTask => { if (syncContext != null) { syncContext.Post(state => { tcs.TrySetFromTask(innerTask); }, state: null); } else { tcs.TrySetFromTask(innerTask); } } , TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously); // this runs only if the inner task faulted task.ContinueWith(innerTask => { if (syncContext != null) { syncContext.Post(state => { try { Task <TResult> resultTask = continuation(); if (resultTask == null) { throw new InvalidOperationException("You cannot return null from the TaskHelpersExtensions.Catch continuation. You must return a valid task or throw an exception."); } tcs.TrySetResult(resultTask); } catch (Exception ex) { tcs.TrySetException(ex); } }, state: null); } else { try { Task <TResult> resultTask = continuation(); if (resultTask == null) { throw new InvalidOperationException("You cannot return null from the TaskHelpersExtensions.Catch continuation. You must return a valid task or throw an exception."); } tcs.TrySetResult(resultTask); } catch (Exception ex) { tcs.TrySetException(ex); } } }, TaskContinuationOptions.OnlyOnFaulted); return(tcs.Task.FastUnwrap()); }
/// <summary>Asynchronously iterates through an enumerable of tasks.</summary> /// <param name="factory">The target factory.</param> /// <param name="source">The enumerable containing the tasks to be iterated through.</param> /// <param name="state">The asynchronous state for the returned Task.</param> /// <param name="cancellationToken">The cancellation token used to cancel the iteration.</param> /// <param name="creationOptions">Options that control the task's behavior.</param> /// <param name="scheduler">The scheduler to which tasks will be scheduled.</param> /// <returns>A Task that represents the complete asynchronous operation.</returns> public static Task Iterate( this TaskFactory factory, IEnumerable <object> source, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { // Validate/update parameters if (factory == null) { throw new ArgumentNullException("factory"); } if (source == null) { throw new ArgumentNullException("asyncIterator"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } // Get an enumerator from the enumerable var enumerator = source.GetEnumerator(); if (enumerator == null) { throw new InvalidOperationException("Invalid enumerable - GetEnumerator returned null"); } // Create the task to be returned to the caller. And ensure // that when everything is done, the enumerator is cleaned up. var trs = new TaskCompletionSource <object>(state, creationOptions); trs.Task.ContinueWith(_ => enumerator.Dispose(), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); // This will be called every time more work can be done. Action <Task> recursiveBody = null; recursiveBody = antecedent => { try { // If we should continue iterating and there's more to iterate // over, create a continuation to continue processing. We only // want to continue processing once the current Task (as yielded // from the enumerator) is complete. if (enumerator.MoveNext()) { var nextItem = enumerator.Current; // If we got a Task, continue from it to continue iterating if (nextItem is Task) { var nextTask = (Task)nextItem; /**/ nextTask.IgnoreExceptions(); // TODO: Is this a good idea? nextTask.ContinueWith(recursiveBody).IgnoreExceptions(); } // If we got a scheduler, continue iterating under the new scheduler, // enabling hopping between contexts. else if (nextItem is TaskScheduler) { Task.Factory.StartNew(() => recursiveBody(null), CancellationToken.None, TaskCreationOptions.None, (TaskScheduler)nextItem).IgnoreExceptions(); } // Anything else is invalid else { trs.TrySetException(new InvalidOperationException("Task or TaskScheduler object expected in Iterate")); } } // Otherwise, we're done! else { trs.TrySetResult(null); } } // If MoveNext throws an exception, propagate that to the user, // either as cancellation or as a fault catch (Exception exc) { var oce = exc as OperationCanceledException; if (oce != null && oce.CancellationToken == cancellationToken) { trs.TrySetCanceled(); } else { trs.TrySetException(exc); } } }; // Get things started by launching the first task factory.StartNew(() => recursiveBody(null), CancellationToken.None, TaskCreationOptions.None, scheduler).IgnoreExceptions(); // Return the representative task to the user return(trs.Task); }
/// <summary> /// Attempts to transition the underlying task into the <see cref="SystemTasks.TaskStatus.Faulted"/> state /// and binds a collection of exception objects to it. /// </summary> public static bool TrySetException(SystemTaskCompletionSource tcs, IEnumerable <Exception> exceptions) => tcs.TrySetException(exceptions);
/// <summary> /// Attempts to transition the underlying task into the <see cref="SystemTasks.TaskStatus.Faulted"/> state /// and binds it to a specified exception. /// </summary> public static bool TrySetException(SystemTaskCompletionSource tcs, Exception exception) => tcs.TrySetException(exception);
public static void Handle <T, R>(this Task <T> task, TaskCompletionSource <R> tcs, Action <T> success) { Handle(task, tcs, success, ex => tcs.TrySetException(ex), () => tcs.TrySetCanceled()); }