| File: ExponentialRetry.cs | Web Access |
| Project: src\sdk\src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj (Microsoft.DotNet.Cli.Utils) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.DotNet.Cli.Utils; public static class ExponentialRetry { public static IEnumerable<TimeSpan> Intervals { get { yield return TimeSpan.FromSeconds(0); // first retry immediately var seconds = 5; while (true) { yield return TimeSpan.FromSeconds(seconds); seconds *= 10; } } } public static IEnumerable<TimeSpan> TestingIntervals { get { while (true) { yield return TimeSpan.FromSeconds(0); } } } public static async Task<T> ExecuteAsyncWithRetry<T>(Func<Task<T>> action, Func<T, bool> shouldStopRetry, int maxRetryCount, Func<IEnumerable<Task>> timer, string taskDescription = "") { var count = 0; foreach (var t in timer()) { await t; T? result = default; count++; result = await action(); if (shouldStopRetry(result)) { return result; } if (count == maxRetryCount) { return result; } } throw new Exception($"Timer for task {taskDescription} should not be exhausted."); } public static async Task<T> ExecuteWithRetry<T>(Func<T> action, Func<T, bool> shouldStopRetry, int maxRetryCount, Func<IEnumerable<Task>> timer, string taskDescription = "") { Func<Task<T>> asyncAction = () => Task.FromResult(action()); return await ExecuteAsyncWithRetry(asyncAction, shouldStopRetry, maxRetryCount, timer, taskDescription); } public static async Task<T> ExecuteWithRetryOnFailure<T>(Func<Task<T>> action, int maxRetryCount = 3, Func<IEnumerable<Task>>? timer = null) { timer = timer ?? (() => Timer(Intervals)); return await ExecuteAsyncWithRetry(action, result => result != null && !result.Equals(default), maxRetryCount, timer); } public static IEnumerable<Task> Timer(IEnumerable<TimeSpan> interval) { return interval.Select(Task.Delay); } }