Example #1
0
 public static void RunUntilCompletion(
     this Task task,
     TimeSpan pollingInterval = default,
     TaskWaitingStrategy taskWaitingStrategy = TaskWaitingStrategy.Sleep)
 {
     task.InternalRunUntilCompletion(pollingInterval, taskWaitingStrategy);
 }
Example #2
0
        /// <summary>
        /// Blocks on a task execution until it's in a <see cref="TaskStatus.Canceled" />, <see cref="TaskStatus.Faulted" />, or <see cref="TaskStatus.RanToCompletion" /> status, will start the task if in <see cref="TaskStatus.Created" />.
        /// </summary>
        /// <typeparam name="T">The type of the return value of the specified task.</typeparam>
        /// <param name="task">Task to wait on.</param>
        /// <param name="pollingInterval">OPTIONAL time to poll and check status of task; DEFAULT is <see cref="DefaultPollingInterval" />.</param>
        /// <param name="taskWaitingStrategy">OPTIONAL strategy on how to wait; DEFAULT is <see cref="TaskWaitingStrategy.Sleep" />.</param>
        /// <returns>
        /// Return value of specified task.
        /// </returns>
        public static T RunUntilCompletion <T>(
            this Task <T> task,
            TimeSpan pollingInterval = default,
            TaskWaitingStrategy taskWaitingStrategy = TaskWaitingStrategy.Sleep)
        {
            task.InternalRunUntilCompletion(pollingInterval, taskWaitingStrategy);

            return(task.Result);
        }
Example #3
0
        private static void InternalRunUntilCompletion(
            this Task task,
            TimeSpan pollingInterval,
            TaskWaitingStrategy taskWaitingStrategy)
        {
            try
            {
                if (task == null)
                {
                    throw new ArgumentNullException(nameof(task));
                }

                var localPollingTime = pollingInterval == default ? DefaultPollingInterval : pollingInterval;

                if (task.Status == TaskStatus.Created)
                {
                    task.Start();
                }

                // running this way because i want to interrogate afterwards to throw if faulted...
                while (!task.IsCompleted && !task.IsCanceled && !task.IsFaulted)
                {
                    switch (taskWaitingStrategy)
                    {
                    case TaskWaitingStrategy.YieldAndSleep:
                        Thread.Yield();
                        Thread.Sleep(pollingInterval);
                        break;

                    case TaskWaitingStrategy.Sleep:
                        Thread.Sleep(pollingInterval);
                        break;

                    default:
                        throw new NotSupportedException(Invariant($"Unsupported {nameof(TaskWaitingStrategy)} - {taskWaitingStrategy}"));
                    }

                    Thread.Sleep(localPollingTime);
                }

                task.IfFaultedTaskExtractAndThrowException();
            }
            catch
            {
                // This is here intentionally as the TPL will sometimes do dumb things...
                throw;
            }
        }
Example #4
0
        /// <summary>
        /// Blocks on a task execution until it's in a <see cref="TaskStatus.Canceled" />, <see cref="TaskStatus.Faulted" />, or <see cref="TaskStatus.RanToCompletion" /> status, will start the task if in <see cref="TaskStatus.Created" />.
        /// </summary>
        /// <param name="task">Task to wait on.</param>
        /// <param name="pollingInterval">Optional time to poll and check status of task; DEFAULT is <see cref="DefaultPollingInterval" />.</param>
        /// <param name="taskWaitingStrategy">Optional strategy on how to wait; DEFAULT is <see cref="TaskWaitingStrategy.Sleep" />.</param>
        public static void TaskUntilCompletion(Task task, TimeSpan pollingInterval = default(TimeSpan), TaskWaitingStrategy taskWaitingStrategy = TaskWaitingStrategy.Sleep)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(task));
            }

            async Task <string> UnnecessaryReturnTaskToReuseReturningObjectCodePath()
            {
                try
                {
                    await task;
                    task.IfNotCompletedThrowException();
                    task.IfFaultedTaskExtractAndThrowException();

                    // This result is not necessary but it is asserted to be the case later so those location must be congruent.
                    // This is to allow for reusing a single code path for both returning and void tasks.
                    return(string.Empty);
                }
                catch
                {
                    // This is here intentionally as the TPL will sometimes do dumb things...
                    throw;
                }
            }

            var unnecessaryResult = TaskUntilCompletion(UnnecessaryReturnTaskToReuseReturningObjectCodePath(), pollingInterval, taskWaitingStrategy);

            if (unnecessaryResult != string.Empty)
            {
                throw new InvalidOperationException(Invariant($"Task was run until completion but it was expected to be a void call and thus during the wrapping should have returned {typeof(string).Name}.{nameof(string.Empty)} but instead it returned '{unnecessaryResult}'."));
            }
        }