Example #1
0
        /// <summary>
        /// It's recommended to use this method (or another TryAwaitOrTimeout or AwaitOrTimeout method)
        /// instead of just Task.WhenAny(taskToAwait, Task.Delay(timeout))
        /// because this method cancels the timer for timeout while <c>Task.Delay(timeout)</c>.
        /// If the number of “zombie” timer jobs starts becoming significant, performance could suffer.
        /// For more detailed explanation see https://devblogs.microsoft.com/pfxteam/crafting-a-task-timeoutafter-method/
        /// </summary>
        /// <returns><c>true</c> if <c>taskToAwait</c> completed before the timeout, <c>false</c> otherwise</returns>
        internal static async Task <bool> TryAwaitOrTimeout(this IAgentTimer agentTimer, Task taskToAwait
                                                            , AgentTimeInstant until, CancellationToken cancellationToken = default
                                                            )
        {
            var timeoutDelayCts  = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            var timeoutDelayTask = agentTimer.Delay(until, timeoutDelayCts.Token);

            try
            {
                var completedTask = await Task.WhenAny(taskToAwait, timeoutDelayTask);

                if (completedTask == taskToAwait)
                {
                    // await taskToAwait to make it throw if taskToAwait is faulted or cancelled so it will throw as it should
                    await taskToAwait;
                    return(true);
                }

                Assertion.IfEnabled?.That(completedTask == timeoutDelayTask
                                          , $"{nameof(completedTask)}: {completedTask}, {nameof(timeoutDelayTask)}: timeOutTask, {nameof(taskToAwait)}: taskToAwait");
                // await timeout task in case it is cancelled and did not timed out so it will throw as it should
                await timeoutDelayTask;
                return(false);
            }
            finally
            {
                if (!timeoutDelayTask.IsCompleted)
                {
                    timeoutDelayCts.Cancel();
                }
                timeoutDelayCts.Dispose();
            }
        }
Example #2
0
        private static void VerifyInstantsAreCompatible(AgentTimeInstant i1, AgentTimeInstant i2, [CallerMemberName] string caller = null)
        {
            if (i1.IsCompatibleWith(i2._sourceAgentTimer))
            {
                return;
            }

            var opName = caller == null ? "an operation" : $"operation {caller}";

            throw new InvalidOperationException($"It's illegal to perform {opName} on two AgentTimeInstant instances " +
                                                "that did not originate from the same timer." +
                                                $" The first AgentTimeInstant: timer: {i1._sourceAgentTimer}, value: {i1._elapsedSinceTimerStarted}." +
                                                $" The second AgentTimeInstant: timer: {i2._sourceAgentTimer}, value: {i2._elapsedSinceTimerStarted}.");
        }
Example #3
0
 public bool Equals(AgentTimeInstant other) =>
 _sourceAgentTimer == other._sourceAgentTimer && _elapsedSinceTimerStarted == other._elapsedSinceTimerStarted;
Example #4
0
        /// <summary>
        /// It's recommended to use this method (or another TryAwaitOrTimeout or AwaitOrTimeout method)
        /// instead of just Task.WhenAny(taskToAwait, Task.Delay(timeout))
        /// because this method cancels the timer for timeout while <c>Task.Delay(timeout)</c>.
        /// If the number of “zombie” timer jobs starts becoming significant, performance could suffer.
        /// For more detailed explanation see https://devblogs.microsoft.com/pfxteam/crafting-a-task-timeoutafter-method/
        /// </summary>
        /// <returns>
        /// (<c>true</c>, result of <c>taskToAwait</c>) if <c>taskToAwait</c> completed before the timeout, <c>false</c>
        /// otherwise
        /// </returns>
        internal static async Task <ValueTuple <bool, TResult> > TryAwaitOrTimeout <TResult>(this IAgentTimer agentTimer, Task <TResult> taskToAwait
                                                                                             , AgentTimeInstant until, CancellationToken cancellationToken = default
                                                                                             )
        {
            var hasTaskToAwaitCompletedBeforeTimeout =
                await TryAwaitOrTimeout(agentTimer, (Task)taskToAwait, until, cancellationToken);

            return(hasTaskToAwaitCompletedBeforeTimeout, hasTaskToAwaitCompletedBeforeTimeout ? await taskToAwait : default);