| | | 1 | | namespace ArturRios.Util.FlowControl.Waiter; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// The exponential-backoff-with-jitter schedule shared by <see cref="JitteredWaiter"/> and |
| | | 5 | | /// <see cref="Retry"/>, so the two cannot drift apart. |
| | | 6 | | /// </summary> |
| | | 7 | | internal static class Backoff |
| | | 8 | | { |
| | | 9 | | /// <summary> |
| | | 10 | | /// Wait applied before the first retry, and the floor every later wait builds on. |
| | | 11 | | /// </summary> |
| | | 12 | | internal const int FixedWaitDelay = 500; |
| | | 13 | | |
| | | 14 | | /// <summary> |
| | | 15 | | /// Computes the delay for a zero-based retry attempt: half the backoff period plus a random half. |
| | | 16 | | /// </summary> |
| | | 17 | | /// <param name="attempt">The zero-based retry attempt.</param> |
| | | 18 | | /// <param name="maxWaitMilliseconds">Ceiling applied to the result.</param> |
| | | 19 | | /// <remarks> |
| | | 20 | | /// The exponent is computed in 64-bit arithmetic and clamped before it is narrowed, so an attempt |
| | | 21 | | /// index large enough to overflow a 32-bit millisecond count simply saturates at |
| | | 22 | | /// <paramref name="maxWaitMilliseconds"/> instead of throwing. |
| | | 23 | | /// </remarks> |
| | | 24 | | internal static int DelayFor(int attempt, int maxWaitMilliseconds) |
| | | 25 | | { |
| | 82 | 26 | | if (attempt <= 0) |
| | | 27 | | { |
| | 11 | 28 | | return System.Math.Min(FixedWaitDelay, maxWaitMilliseconds); |
| | | 29 | | } |
| | | 30 | | |
| | | 31 | | // 2^52 milliseconds already dwarfs any sane ceiling, so shifting further would only overflow. |
| | 71 | 32 | | var backoffPeriodMs = attempt >= 52 |
| | 71 | 33 | | ? long.MaxValue / 2L |
| | 71 | 34 | | : (1L << attempt) * 1000L - FixedWaitDelay; |
| | | 35 | | |
| | 71 | 36 | | var half = backoffPeriodMs / 2L; |
| | 71 | 37 | | var jitter = half > 0L ? System.Random.Shared.NextInt64(0L, half) : 0L; |
| | | 38 | | |
| | 71 | 39 | | return (int)System.Math.Min(FixedWaitDelay + half + jitter, maxWaitMilliseconds); |
| | | 40 | | } |
| | | 41 | | } |