Skip to content

Commit

Permalink
core: add ExponentialRandomizedBackoff.AdvanceBy to compute the next …
Browse files Browse the repository at this point in the history
…DateTime/Instant

- Helper that adds GetNext() to an Instant, DateTime or DateTimeOffset
  • Loading branch information
KrzysFR committed Jul 5, 2024
1 parent 8e399fb commit 24307c9
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions Doxense.Core/Threading/ExponentialRandomizedBackoff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace Doxense.Threading
{
using NodaTime;

/// <summary>Provides a state machine that can be used to retry operations after a randomized delay with built-in exponential backoff</summary>
public sealed class ExponentialRandomizedBackoff
Expand Down Expand Up @@ -108,6 +109,73 @@ public TimeSpan GetNext()
return GetNext(out _);
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <param name="iterations">Number of calls to this method since the last <see cref="Reset"/></param>
/// <returns>Instant in the future with a randomized delay</returns>
public Instant AdvanceBy(Instant now, out int iterations)
{
var delay = GetNext(out iterations);
return now.Plus(Duration.FromTimeSpan(delay));
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <returns>Instant in the future with a randomized delay</returns>
public Instant AdvanceBy(Instant now)
{
var delay = GetNext();
return now.Plus(Duration.FromTimeSpan(delay));
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <param name="iterations">Number of calls to this method since the last <see cref="Reset"/></param>
/// <returns>Instant in the future with a randomized delay</returns>
public DateTimeOffset AdvanceBy(DateTimeOffset now, out int iterations)
{
var delay = GetNext(out iterations);
return now + delay;
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <returns>Instant in the future with a randomized delay</returns>
public DateTimeOffset AdvanceBy(DateTimeOffset now)
{
var delay = GetNext();
return now + delay;
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <param name="iterations">Number of calls to this method since the last <see cref="Reset"/></param>
/// <returns>Instant in the future with a randomized delay</returns>
public DateTimeOffset AdvanceBy(DateTime now, out int iterations)
{
var delay = GetNext(out iterations);
return now + delay;
}

/// <summary>Computes the earliest instant when the next operation should be attempted again</summary>
/// <param name="now">Current time</param>
/// <returns>Instant in the future with a randomized delay</returns>
public DateTimeOffset AdvanceBy(DateTime now)
{
var delay = GetNext();
return now + delay;
}

/// <summary>Computes the next instant after a randomized delay</summary>
/// <param name="now">Current time</param>
/// <param name="baseDelay">Base delay (before randomization)</param>
/// <param name="low">Minimum randomized factor applied to the base delay (must be greater than 0, defaults to 1)</param>
/// <param name="high">Maximum randomzed factor applied to the base delay (must be greater or eqaul to <paramref name="low"/>, defaults to 1.5)</param>
/// <param name="rng">Pseudo-random number generator used to compute the delay</param>
/// <returns>Instant in the future that is after <paramref name="now"/> by a randomized delay 'd' that is equal to the <paramref name="baseDelay">base delay</paramref>, multiplied by a random factor between <paramref name="low"/> and <paramref name="high"/></returns>
public static Instant AdvanceBy(Instant now, TimeSpan baseDelay, double low = 1.0d, double high = 1.5d, Random? rng = null)
=> now.Plus(Duration.FromTimeSpan(GetNext(baseDelay, low, high, rng)));

/// <summary>Reset the delay to the initial value, following a successfull operation.</summary>
/// <remarks>
/// <para>This method should either be called at the start of a new request, or after a successful request, to reset the current state.</para>
Expand Down

0 comments on commit 24307c9

Please sign in to comment.