• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ThreeMammals / Ocelot / 23302213965

19 Mar 2026 03:19PM UTC coverage: 91.219% (-1.3%) from 92.49%
23302213965

Pull #2369

github

web-flow
Merge 7f6f01146 into 086c7b15c
Pull Request #2369: Pre-Release 25.0 aka Beta 2

8404 of 9213 relevant lines covered (91.22%)

2131.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/Ocelot/Infrastructure/DesignPatterns/Retry.cs
1
using Ocelot.Logging;
2

3
namespace Ocelot.Infrastructure.DesignPatterns;
4

5
/// <summary>
6
/// Basic <seealso href="https://www.bing.com/search?q=Retry+pattern">Retry pattern</seealso> for stabilizing integrated services.
7
/// </summary>
8
/// <remarks>Docs:
9
/// <list type="bullet">
10
/// <item><see href="https://learn.microsoft.com/en-us/azure/architecture/patterns/retry">Microsoft Learn | Retry pattern</see></item>
11
/// </list>
12
/// </remarks>
13
public static class Retry
14
{
15
    public const int DefaultRetryTimes = 3;
16
    public const int DefaultWaitTimeMilliseconds = 25;
17

18
    private static string GetMessage<T>(T operation, int retryNo, string message)
19
        where T : Delegate
20
        => $"Ocelot {nameof(Retry)} strategy for the operation of '{operation.GetType()}' type -> {nameof(Retry)} No {retryNo}: {message}";
×
21

22
    /// <summary>
23
    /// Retry a synchronous operation when an exception occurs or predicate is true, then delay and retry again.
24
    /// </summary>
25
    /// <typeparam name="TResult">Type of the result of the sync operation.</typeparam>
26
    /// <param name="operation">Required Func-delegate of the operation.</param>
27
    /// <param name="predicate">Predicate to check, optionally.</param>
28
    /// <param name="retryTimes">Number of retries.</param>
29
    /// <param name="waitTime">Waiting time in milliseconds.</param>
30
    /// <param name="logger">Concrete logger from upper context.</param>
31
    /// <returns>A <typeparamref name="TResult"/> value as the result of the sync operation.</returns>
32
    public static TResult Operation<TResult>(
33
        Func<TResult> operation,
34
        Predicate<TResult> predicate = null,
35
        int retryTimes = DefaultRetryTimes, int waitTime = DefaultWaitTimeMilliseconds,
36
        IOcelotLogger logger = null)
37
    {
×
38
        if (waitTime < 0)
×
39
        {
×
40
            waitTime = 0; // 0 means no thread sleeping
×
41
        }
×
42

43
        for (int n = 1; n < retryTimes; n++)
×
44
        {
×
45
            TResult result;
46
            try
47
            {
×
48
                result = operation.Invoke();
×
49
            }
×
50
            catch (Exception e)
×
51
            {
×
52
                logger?.LogError(() => GetMessage(operation, n, $"Caught exception of the {e.GetType()} type -> Message: {e.Message}."), e);
×
53
                Thread.Sleep(waitTime);
×
54
                continue; // the result is unknown, so continue to retry
×
55
            }
56

57
            // Apply predicate for known result
58
            if (predicate?.Invoke(result) == true)
×
59
            {
×
60
                logger?.LogWarning(() => GetMessage(operation, n, $"The predicate has identified erroneous state in the returned result. For further details, implement logging of the result's value or properties within the predicate method."));
×
61
                Thread.Sleep(waitTime);
×
62
                continue; // on erroneous state
×
63
            }
64

65
            // Happy path
66
            return result;
×
67
        }
68

69
        // Last retry should generate native exception or other erroneous state(s)
70
        logger?.LogDebug(() => GetMessage(operation, retryTimes, $"Retrying lastly..."));
×
71
        return operation.Invoke(); // also final result must be analyzed in the upper context
×
72
    }
×
73

74
    /// <summary>
75
    /// Retry an asynchronous operation when an exception occurs or predicate is true, then delay and retry again.
76
    /// </summary>
77
    /// <typeparam name="TResult">Type of the result of the async operation.</typeparam>
78
    /// <param name="operation">Required Func-delegate of the operation.</param>
79
    /// <param name="predicate">Predicate to check, optionally.</param>
80
    /// <param name="retryTimes">Number of retries.</param>
81
    /// <param name="waitTime">Waiting time in milliseconds.</param>
82
    /// <param name="logger">Concrete logger from upper context.</param>
83
    /// <returns>A <typeparamref name="TResult"/> value as the result of the async operation.</returns>
84
    public static async Task<TResult> OperationAsync<TResult>(
85
        Func<Task<TResult>> operation, // required operation delegate
86
        Predicate<TResult> predicate = null, // optional retry predicate for the result
87
        int retryTimes = DefaultRetryTimes, int waitTime = DefaultWaitTimeMilliseconds, // retrying options
88
        IOcelotLogger logger = null) // static injections
89
    {
×
90
        for (int n = 1; n < retryTimes; n++)
×
91
        {
×
92
            TResult result;
93
            try
94
            {
×
95
                result = await operation?.Invoke();
×
96
            }
×
97
            catch (Exception e)
×
98
            {
×
99
                logger?.LogError(() => GetMessage(operation, n, $"Caught exception of the {e.GetType()} type -> Message: {e.Message}."), e);
×
100
                await (waitTime > 0 ? Task.Delay(waitTime) : Task.CompletedTask);
×
101
                continue; // the result is unknown, so continue to retry
×
102
            }
103

104
            // Apply predicate for known result
105
            if (predicate?.Invoke(result) == true)
×
106
            {
×
107
                logger?.LogWarning(() => GetMessage(operation, n, $"The predicate has identified erroneous state in the returned result. For further details, implement logging of the result's value or properties within the predicate method."));
×
108
                await (waitTime > 0 ? Task.Delay(waitTime) : Task.CompletedTask);
×
109
                continue; // on erroneous state
×
110
            }
111

112
            // Happy path
113
            return result;
×
114
        }
115

116
        // Last retry should generate native exception or other erroneous state(s)
117
        logger?.LogDebug(() => GetMessage(operation, retryTimes, $"Retrying lastly..."));
×
118
        return await operation?.Invoke(); // also final result must be analyzed in the upper context
×
119
    }
×
120
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc