Пример #1
0
        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));
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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());
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
 /// <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);
Пример #6
0
 /// <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);
Пример #7
0
 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());
 }