-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
ExponentialRetry.cs
84 lines (75 loc) · 2.58 KB
/
ExponentialRetry.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// 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 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 == null ? () => Timer(Intervals) : timer;
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);
}
}
}