An abstraction of utilities for retrying with exponential back off and jitter.
Overview
The retry utilities are a set of APIs that aid in retrying with exponential backoff and jitter. Exponential backoff with jitter is strongly recommended for retrying failed actions over the network with servers. Please see https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ for more information about the benefits with AWS.
Exponential backoff with jitter is typically used when retrying a failed connection to the server. In an environment with poor connectivity, a client can get disconnected at any time. A backoff strategy helps the client to conserve battery by not repeatedly attempting reconnections when they are unlikely to succeed.
Before retrying the failed communication to the server, there is a delay period. In this delay period, the task that is retrying must sleep for some random amount of seconds between 0 and the lesser of the backoff window (related to the retry attempt) and a predefined maximum delay value. The backoff window is doubled with each retry attempt until the maximum delay value is reached.
sleep_seconds = random_between( 0, min( 2attempts_count * base_seconds, maximum_seconds ) )
Implementing Retry Utils
The functions that must be implemented are:
The functions are used as shown in the diagram below. This is the exponential backoff with jitter loop:
The following steps give guidance on implementing the Retry Utils. An example implementation of the Retry Utils for a POSIX platform can be found in file retry_utils_posix.c.
- Implementing RetryUtils_ParamsReset
This function initializes RetryUtilsParams_t. It is expected to set RetryUtilsParams_t::attemptsDone to zero. It is also expected to set RetryUtilsParams_t::nextJitterMax to INITIAL_RETRY_BACKOFF_SECONDS plus some random amount of seconds, jitter. This jitter is a random number between 0 and MAX_JITTER_VALUE_SECONDS. This function must be called before entering the exponential backoff with jitter loop using RetryUtils_BackoffAndSleep.
Please follow the example below to implement your own RetryUtils_ParamsReset. The lines with FIXME comments should be updated.
{
uint32_t jitter = 0;
srand( time( NULL ) );
}
- Implementing RetryUtils_BackoffAndSleep
When this function is invoked, the calling task is expected to sleep a random number of seconds between 0 and RetryUtilsParams_t::nextJitterMax. After sleeping this function must double RetryUtilsParams_t::nextJitterMax, but not exceeding MAX_RETRY_BACKOFF_SECONDS. When MAX_RETRY_ATTEMPTS are reached, this function should return RetryUtilsRetriesExhausted, unless MAX_RETRY_ATTEMPTS is set to zero. When RetryUtilsRetriesExhausted is returned, the calling application can stop trying with a failure, or it can call RetryUtils_ParamsReset again, and restart the exponential back off with jitter loop.
Please follow the example below to implement your own RetryUtils_BackoffAndSleep. The lines with FIXME comments should be updated.
{
int backOffDelay = 0;
{
( void ) myThreadSleepFunction( backOffDelay );
{
}
else
{
}
}
else
{
}
return status;
}