Luger.Async.ExponentialBackoff 1.0.0

dotnet add package Luger.Async.ExponentialBackoff --version 1.0.0
                    
NuGet\Install-Package Luger.Async.ExponentialBackoff -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Luger.Async.ExponentialBackoff" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Luger.Async.ExponentialBackoff" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Luger.Async.ExponentialBackoff" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Luger.Async.ExponentialBackoff --version 1.0.0
                    
#r "nuget: Luger.Async.ExponentialBackoff, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Luger.Async.ExponentialBackoff&version=1.0.0
                    
Install Luger.Async.ExponentialBackoff as a Cake Addin
#tool nuget:?package=Luger.Async.ExponentialBackoff&version=1.0.0
                    
Install Luger.Async.ExponentialBackoff as a Cake Tool

Luger.Async.ExponentialBackoff

Utility for configuring and awaiting exponential backoff over asynchronous functions.

That is all it does. If you're looking for a robust tool with this functionality and much more you should have a look at Polly.

Exponential backoff is an algorithm that uses feedback to multiplicatively decrease the rate of some process, in order to gradually find an acceptable rate. <sup>Wikipedia page Exponential Backoff (this version)</sup>

Luger.Async.ExponentialBackoff provides an implementation that retries an asynchronous function (process) after an increasingly longer delay (multiplicatively decrease the rate) if it fails (feedback) in order to mitigate transient failures.

Usage

Wrap an asynchronous function func in exponential backoff with default options and await it.

await ExponentialBackoff.Over(func);

The return type will be T for func of type Func<Task<T>>. The return type will be System.ValueTuple for func of type Func<Task>.

Exponential backoff can be configured before await by calling methods making up its fluent configuration API.

await ExponentialBackoff.Over(func).WithRetries(2);

Configuration

Limit number of retries

Number of retries before giving up and throwing the last encountered exception.

WithRetries(uint retries)

Default limit number of retries is 8.

Base delay

The mean duration of the first delay before retrying.

WithBaseDelay(DelayTimeSpan baseDelay)

Default base delay is 100 ms.

DelayTimeSpan is a non-negative System.TimeSpan.

Synchronization context marshalling

Configure exponential backoff to attempt to marshal the delays and retries back to the original context captured.

ConfigureRetryAwait(bool retryOnCapturedContext)

Default is to not attempt to marshal back to the original context captured.

Custom random number generation

Inject a custom random number generator.

WithCustomRNG(RNG rng)

Default random number generator is System.Random.NextDouble with a fresh instance of System.Random shared by all iterations of one single exponential backoff.

The random number generator is expected to produce values in the range $[0..1)$. Values outside this range will cause an exception to be thrown.

RNG has the following declaration;

delegate double RNG();

Progress reporting

Inject a progress reporting sink.

WithProgress(IProgress<ExponentialBackoffProgress> progress)

Default is to not report progress.

If you need to have progress reporting performed according to a specific synchronization context (e.g. for updating WinForm GUI elements on the GUI thread) it's advisable to use System.Progress<T> as it uses the synchronization context captured at construction.

ExponentialBackoffProgress has the following declaration;

record struct ExponentialBackoffProgress(
    uint Retries,
    TimeSpan BackoffDelay,
    Exception Exception);

If configured, progress is reported before each delay. Retries is the number of retries left. BackoffDelay is the duration of this delay. Exception is the exception caught from the recent await of the asynchronous function.

Custom delay implementation

Inject a custom delay implementation.

WithCustomDelay(Delay delay)

Default delay implementation is System.Threading.Task.Delay.

This configuration is only useful for testing purposes when you want deterministic control over execution and therefore want to isolate from environmental concerns like time.

Another possible use of custom delay would be to use spin wait in high performance scenarios, but in that case it would be better to implement a more suitable exponential backoff to avoid the overhead of wrapping the function and delay in Task. This implementation is better suited for mitigating I/O with transient failures.

Delay has the following declaration;

delegate Task Delay(TimeSpan delay, CancellationToken cancellationToken);

Delay scale factor

Set scale factor to multiply mean delay duration with each iteration.

WithFactor(TimeScaleFactor factor)

Default is $2.0$.

TimeScaleFactor is a finite, non-negative double.

Cancellation

Set cancellation token with which to cancel exponential backoff.

WithCancellation(CancellationToken cancellationToken)

Default is CancellationToken.None.

If configured, this cancellation token is used by the delay. It is not automatically monitored by the asynchronous function. If you need the asynchronous function to monitor the same cancellation token you have to configure its cancellation separately.

Details

The exponential scaling of backoff duration affects the mean durations of the delays.

The effective durations of the delays are the mean durations multiplied by a random jitter factor. The jitter factor is exponentially distributed with mean 1.0 . The reason for this is, I don't know, it's more interesting than uniform distribution.

In theory this can result in very long delays. If this becomes a practical problem, or if someone constructively points out how stupid this is, it will be changed.

If you want the jitter factor to be constant, inject a constant random number generator.

If you want the jitter factor to be constant 1.0, inject a constant random number generator producing $1-e^{-1}$.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 107 2 months ago
1.0.0-beta 168 1/7/2023