public static class TaskExtensions { /// /// The given task will be retried a given number of times. In case of failure a delay is introduced before executing the retry. /// public static async Task Retry( this Func> taskFactory, int maxRetries, TimeSpan delay) { for (var i = 1; i <= maxRetries; i++) { try { return await taskFactory(); } catch { if (i == maxRetries) throw; await Task.Delay(delay); } } throw new InvalidOperationException(); } /// /// Throws a when the given tasks takes longer than the specified time span. /// public static async Task Timeout(this Task task, TimeSpan timeSpan, CancellationToken cancellationToken) { var timeoutTask = Task.Delay(timeSpan, cancellationToken); var completedTask = await Task.WhenAny(task, timeoutTask); if (completedTask == timeoutTask) { throw new TimeoutException(); } return task.Result; } /// /// Executes an error handler in case the task encounters an exception. /// public static async Task OnFailure(this Task task, Action errorHandler) { try { await task; } catch (Exception ex) { errorHandler?.Invoke(ex); } } /// /// Fire and forget a task with an optional error handler. /// public static void FireAndForget(this Task task, Action? errorHandler = null) { task.ContinueWith(t => { if (t.Exception != null && errorHandler != null) { errorHandler(t.Exception); } }, TaskContinuationOptions.OnlyOnFaulted); } }