/// <summary> /// Run a sync action synchoronously with a timeout and some additional ooptions. /// </summary> /// <param name="syncAction">The sync action to execute.</param> /// <param name="timeout">The timeout to apply.</param> /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param> /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out action.</param> /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param> public static void RunSyncActionWithTimeout(Action <CancellationToken> syncAction, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task>?timedOutTaskProcessor = null, CancellationToken token = default) { token.ThrowIfCancellationRequested(); if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan) { var exc = new SyntheticTimeoutException(); if (cancelIfTimeout == false) { timedOutTaskProcessor?.Invoke(Task.FromException(exc)); } throw exc; } Task task; if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None) { //task = _taskFactory.StartNew(() => syncAction(token), token); syncAction(token); return; } else { task = RunAsyncActionWithTimeoutAsync(ct => _taskFactory.StartNew(() => syncAction(ct), ct), timeout, cancelIfTimeout, timedOutTaskProcessor, token); } task.GetAwaiter().GetResult(); }
/// <summary> /// Run an async function synchoronously with a timeout and some additional ooptions. /// </summary> /// <typeparam name="TResult"></typeparam> /// <param name="asyncFunc">The async function to execute.</param> /// <param name="timeout">The timeout to apply.</param> /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param> /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out function.</param> /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param> /// <returns>The value returned from the async function</returns> public static TResult RunAsyncFuncWithTimeout <TResult>(Func <CancellationToken, Task <TResult> > asyncFunc, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task <TResult> >?timedOutTaskProcessor = null, CancellationToken token = default) { token.ThrowIfCancellationRequested(); if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan) { var exc = new SyntheticTimeoutException(); if (cancelIfTimeout == false) { timedOutTaskProcessor?.Invoke(Task.FromException <TResult>(exc)); } throw exc; } Task <TResult> task; if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None) { task = _taskFactory.StartNew(() => asyncFunc(token), token).Unwrap(); } else { task = _taskFactory.StartNew(() => RunAsyncFuncWithTimeoutAsync(asyncFunc, timeout, cancelIfTimeout, timedOutTaskProcessor, token), token).Unwrap(); } return(task.GetAwaiter().GetResult()); }
/// <summary> /// Run an async function asynchronously with a timeout and some additional ooptions. /// </summary> /// <typeparam name="TResult"></typeparam> /// <param name="asyncFunc">The async function to execute.</param> /// <param name="timeout">The timeout to apply.</param> /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param> /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out function.</param> /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param> /// <returns>The resulting <see cref="Task"/> to await</returns> public static async Task <TResult> RunAsyncFuncWithTimeoutAsync <TResult>(Func <CancellationToken, Task <TResult> > asyncFunc, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task <TResult> >?timedOutTaskProcessor = null, CancellationToken token = default) { token.ThrowIfCancellationRequested(); if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan) { var exc = new SyntheticTimeoutException(); if (cancelIfTimeout == false) { timedOutTaskProcessor?.Invoke(Task.FromException <TResult>(exc)); } throw exc; } if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None) { return(await asyncFunc(token).ConfigureAwait(false)); } var ctsFunc = cancelIfTimeout ? CancellationTokenSource.CreateLinkedTokenSource(token) : null; try { using (var ctsDelay = CancellationTokenSource.CreateLinkedTokenSource(token)) { var funcTask = asyncFunc(ctsFunc?.Token ?? token); using (var delayTask = Task.Delay(timeout, ctsDelay.Token)) { await Task.WhenAny(funcTask, delayTask).ConfigureAwait(false); if (delayTask.IsCompleted == false && delayTask.IsFaulted == false) { ctsDelay.Cancel(); } } if (funcTask.IsCompleted == false && funcTask.IsFaulted == false) { ctsFunc?.Cancel(); } token.ThrowIfCancellationRequested(); if (funcTask.IsCompleted) { return(await funcTask.ConfigureAwait(false)); } if (cancelIfTimeout == false) { timedOutTaskProcessor?.Invoke(funcTask); } throw new SyntheticTimeoutException(); } } finally { ctsFunc?.Dispose(); } }