Download the PHP package code-distortion/backoff without Composer

On this page you can find all versions of the php package code-distortion/backoff. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package backoff

Backoff

Latest Version on Packagist PHP Version GitHub Workflow Status Buy The World a Tree

code-distortion/backoff is a PHP library that retries your actions when they fail. It implements various backoff strategies and jitter to avoid overwhelming the resource being accessed.

It's useful when you're working with services that might be temporarily unavailable, such as APIs.

See the cheatsheet for an overview of what's possible.

Table of Contents

Installation

Install the package via composer:

General Backoff Tips

Further Reading

Cheatsheet

Quick examples…

Start by picking an algorithm to use…

Then customise the retry logic…

Retry only in certain situations if you'd like…

Add callbacks if desired…

And finally, run your work…

Usage

Start by:

By default, your closure will be retried when exceptions occur. The value returned by your closure will be returned when it succeeds.

When exceptions occur, the final exception is rethrown.

However, you can pass a default value to return instead.

Note: $default may be a callable that returns the default value. It will only be called when the default value is needed.

Backoff Algorithms

Backoff algorithms are used to calculate how long to wait between attempts. They usually increase the delay between attempts in some way.

Note: The actual delays will vary because Thundering Herd problem by making retries less predictable.

By default, delays are in seconds. However, each algorithm has millisecond and microsecond variations.

Note: Delays in any unit-of-measure can have decimal places, including seconds.

Note: Microseconds are probably small enough that the numbers start to become inaccurate because of PHP overheads when sleeping. For example, on my computer, while code can run quicker than a microsecond, running usleep(1) to sleep for 1 microsecond actually takes about 55 microseconds.

A number of backoff algorithms have been included to choose from, and you can also create your own…

Fixed Backoff

The fixed backoff algorithm waits the same amount of time between each attempt.

Linear Backoff

The linear backoff algorithm increases the waiting period by a specific amount each time.

If $delayIncrease is not passed, it will increase by $initalDelay each time.

Logic: $delay = $initialDelay + (($retryNumber - 1) * $delayIncrease)

Exponential Backoff

The exponential backoff algorithm increases the waiting period exponentially.

By default, the delay is doubled each time, but you can change the factor it multiplies by.

Logic: $delay = $initialDelay * pow($factor, $retryNumber - 1)

Polynomial Backoff

The polynomial backoff algorithm increases the waiting period in a polynomial manner.

By default, the retry number is raised to the power of 2, but you can change this.

Logic: $delay = $initialDelay * pow($retryNumber, $power)

Fibonacci Backoff

The Fibonacci backoff algorithm increases waiting period by following a Fibonacci sequence. This is where each delay is the sum of the previous two delays.

Logic: $delay = $previousDelay1 + $previousDelay2

Seeing as the first and second delays in a Fibonacci sequence are the same, you can choose to skip the first delay if you like.

Decorrelated Backoff

The decorrelated backoff algorithm is a feedback loop where the previous delay is used as input to help to determine the next delay.

A random delay between the $baseDelay and the previous-delay * 3 is picked.

Jitter is not applied to this algorithm.

Logic: $delay = rand($baseDelay, $prevDelay * $multiplier)

Info: The article Exponential Backoff And Jitter by Marc Brooker at AWS explains Decorrelated Backoff in more detail.

Random Backoff

The random backoff algorithm waits for a random period of time within the range you specify.

Jitter is not applied to this algorithm.

Logic: $delay = rand($min, $max)

Sequence Backoff

The sequence backoff algorithm lets you specify the particular delays to use.

An optional fixed delay can be used to continue with, after the sequence finishes. Otherwise, the attempts will stop when the sequence has been exhausted.

Note: You'll need to make sure the delay values you specify match the unit-of-measure being used.

Logic: $delay = $delays[$retryNumber - 1]

Note: If you use ->immediateFirstRetry(), one extra retry will be made before your sequence starts.

Callback Backoff

The callback backoff algorithm lets you specify a callback that chooses the period to wait.

Your callback is expected to return an int or float representing the delay, or null to indicate that the attempts should stop.

Logic: $delay = $callback($retryNumber, $prevBaseDelay)

Note: You'll need to make sure the delay values you return match the unit-of-measure being used.

Note: If you use ->immediateFirstRetry(), one extra retry will be made before your callback is used.

In this case, $retryNumber will start with 1, but it will really be for the second attempt onwards.

Custom Backoff Algorithm Class

As well as the callback option above, you have the ability to create your own backoff algorithm class by extending BaseBackoffAlgorithm and implementing the BackoffAlgorithmInterface.

Then use your custom backoff algorithm like this:

Note: You'll need to make sure the delay values you return match the unit-of-measure being used.

Note: If you use ->immediateFirstRetry(), an extra retry will be made before your algorithm is used.

In this case, $retryNumber will start with 1, but it will really be for the second attempt onwards.

Noop Backoff

The "no-op" backoff algorithm is a utility algorithm that doesn't wait at all, retries are attempted straight away.

This might be useful for testing purposes. See Working With Test Suites for more options when running tests.

No Backoff

The "no backoff" algorithm is a utility algorithm that doesn't allow retries at all. Only the first attempt will be made.

This might be useful for testing purposes. See Working With Test Suites for more options when running tests.

Configuration (Customise the Retry Logic)

Max Attempts

By default, Backoff will retry forever. To stop this from happening, you can specify the maximum number of attempts allowed.

Delay

Max-Delay

You can specify the maximum length each base-delay can be (which is the delay before jitter is applied). This will prevent the delays from becoming too large.

Note: You'll need to make sure the max-delay you specify matches the unit-of-measure being used.

Immediate First Retry

If you'd like your first retry to occur immediately after the first failed attempt, you can add an initial 0 delay by calling ->immediateFirstRetry(). This will be inserted before the normal backoff delays start.

This won't affect the maximum attempt limit. So if you set a maximum of 5 attempts, and you use ->immediateFirstRetry(), there will still be up to 5 attempts in total.

Jitter

Having a backoff algorithm is a good start but probably isn't enough to prevent a stampede on its own. This is called the Thundering Herd problem and can still happen when clients synchronise their attempts at the same moments in time.

Jitter is used to mitigate this by making random adjustments to the Backoff Algorithm's delays.

For example, if the backoff algorithm generates a delay of 100ms, jitter could randomly adjust this to be somewhere between say, 75ms and 125ms. The actual range depends on the type of jitter used.

This library applies No Jitter.

The article Exponential Backoff And Jitter by Marc Brooker at AWS does a good job of explaining what jitter is, and the reason for its use.

Full Jitter

Full Jitter applies a random adjustment to the delay, within the range of 0 and the full delay. That is, between 0% and 100% of the base-delay.

Note: This is the type of jitter that is used by default.

$delay = rand(0, $delay)

Equal Jitter

Equal Jitter applies a random adjustment to the delay, within the range of half and the full delay. That is, between 50% and 100% of the base-delay.

$delay = rand($delay / 2, $delay)

Custom Jitter Range

If you'd like a different range compared to full and equal jitter above, jitter-range lets you specify your own custom range.

$delay = rand($delay * $min, $delay * $max)

Jitter Callback

Jitter callback lets you specify a callback that applies jitter to the base-delay.

Your callback is expected to return an int or float representing the updated delay.

$delay = $callback($delay, $retryNumber)

Custom Jitter Class

As well as customising jitter using the callback options above, you have the ability to create your own Jitter class by extending BaseJitter and implementing the JitterInterface.

You can then use your custom jitter class like this:

No Jitter

Full Jitter is applied by default, however you can turn it off by calling ->noJitter().

When disabled, the base-delays generated by the max-delay is applied).

Managing Exceptions

By default, Backoff will retry whenever an exception occurs. You can customise this behaviour using the following methods.

Retry When Any Exception Occurs

Retry all exceptions - this is actually the default behaviour, so you don't need to call it (unless you've previously set it to something else).

By default, when all attempts have failed (e.g. when ->maxAttempts(…) is used), the final exception is rethrown afterwards.

You can pass a default value to return instead when that happens.

Note: $default may be a callable that returns the default value. It will only be called when the default value is needed.

Retry When Particular Exceptions Occur

You can specify particular exception types to catch and retry, along with the optional $default value to return if all attempts fail.

If you'd like to specify more than one, you can pass them in an array, or call it multiple times. You can specify a different $default value each call.

Note: $default may be a callable that returns the default value. It will only be called when the default value is needed.

You can also pass a callback that chooses whether to retry or not. The exception will be passed to your callback, and it should return true to try again, or false to end.

Don't Retry When Exceptions Occur

And finally, you can turn this off so retries are not made when exceptions occur.

Normally, the exception will be rethrown. However, you can pass a $default value to return instead.

Note: $default may be a callable that returns the default value. It will only be called when the default value is needed.

Managing "Invalid" Return Values

By default, Backoff will not retry based on your $action's return value. However, it can if you like.

Retry When…

This will retry whenever $action's return value matches the specified $match value.

$strict allows you to choose whether to compare with $match using strict (===) or loose (==) comparison.

You can specify a $default value to return if all attempts fail.

When you don't specify a default, the final value returned by $action will be returned.

You can also pass a callback that chooses whether to retry or not. Your callback should return true to try again, or false to stop.

Note: $strict has no effect when using a callback.

Note: $default may be a callable that returns the default value. It will only be called when the default value is needed.

Retry Until…

Conversely to ->retryWhen(), you can specify $match value/s to wait for. Retries will be made until there's a match.

Similarly, $strict allows you to compare the returned value to $value using strict (===) or loose (==) comparison.

You can also specify a callback that chooses whether to retry or not. Contrasting with ->retryWhen() above, your callback should return false to try again, or true to stop.

Note: $strict has no effect when using a callback.

Note: You can't specify a default value for retry until, but you can still pass one to ->attempt($action, $default).

Callbacks

Several callback options are available which get triggered at different points in the attempt lifecycle.

Note: Backoff can pass an AttemptLog object (or an array of all of them) to your callbacks. These contain information about the attempt/s that have been made. See below for information about the AttemptLog class.

Note: You can specify multiple callbacks at a time by passing them as an array, or by calling the method multiple times.

The callbacks will be called in the order they were added.

Exception Callback

If you'd like to run some code every time an exception occurs, you can pass a callback to ->exceptionCallback(…).

It doesn't matter if the exception is caught using ->retryExceptions(…) or not. These callbacks will be called regardless of a retry being made afterwards.

Note: You can specify different callbacks by passing multiple callbacks or calling ->exceptionCallback(…) multiple times. Type-hint the $exception parameter differently each time. e.g.

Callbacks that match the exception type will be called.

Invalid Result Callback

If you'd like to run some code each time an invalid result is returned, you can pass a callback to ->invalidResultCallback(…).

Success Callback

You can specify a callback to be called after the attempt/s succeed by calling ->successCallback(…).

Failure Callback

You can specify a callback to be called after all attempts have failed by calling ->failureCallback(…).

This includes if zero attempts were made, and when an exception is eventually thrown.

Finally Callback

If you would like to run some code afterwards, regardless of the outcome, you can pass a callback to ->finallyCallback(…).

This includes if zero attempts were made, and when an exception is eventually thrown.

Logging

Backoff collects some basic information about each attempt and makes them available for you to log. You will need to handle the logging yourself.

This history is made up of callbacks.

Note: If you extra ways to interact with these logs.

The AttemptLog Class

The AttemptLog class contains basic information about each attempt that has happened.

They contain the following methods:

Working With Test Suites

When running your test-suite, you might want to disable the backoff delays, or stop retries altogether.

Disabling Backoff Delays

You can remove the delay between attempts using ->onlyDelayWhen(false).

The action may still be retried, but there won't be any delays between attempts.

When $runningTests is true, this is:

  • equivalent to setting ->maxDelay(0), and
  • is largely equivalent to using the Backoff::noop() backoff.

Disabling Retries

Alternatively, you can disable retries altogether using ->onlyRetryWhen(false).

When $runningTests is true, this is equivalent to:

  • setting ->maxAttempts(1), or
  • using the Backoff::none() backoff algorithm.

Managing the Retry Loop Yourself

If you'd like more control over the process, you can manage the retry loop yourself. This involves setting up a loop, and using Backoff to handle the delays each iteration.

Please note that by doing this, you're skipping the part of Backoff that manages the loop and retry process. You're essentially handling them yourself.

This means that you won't be able to use Backoff's functionality to:

If your aim is to do one of the following, you could use one of the already available options:

  • ->retryExceptions(…). This lets you specify which exceptions to retry, or specify a callback to make the decision.
  • ->retryUntil(…). These let you specify values to check for, or specify a callback to make the decision.
  • ->invalidResultCallback(…).

The Basic Loop

Start by:

If you'd like to attempt your action zero or more times, you can place $backoff->step() at the entrance of your loop, having called ->runsAtStartOfLoop() beforehand.

This lets Backoff know, so it doesn't perform the delay and count the attempt the first time.

Catching Exceptions in Your Loop

Add a try-catch block to handle exceptions inside your loop, and handle the exception as you see fit.

Deconstructing the Backoff Logic

You can separate the process into its parts if you'd like to have even more control over the process.

->step() normally performs the sleep, but you can call ->step(false) to skip the sleep, and then perform the sleep separately by calling ->sleep().

You can also perform the sleep yourself (instead of calling ->sleep()).

Call ->getDelayInSeconds(), ->getDelayInMs(), or ->getDelayInUs() to retrieve the delay in the unit-of-measure you need.

Working With Logs

When managing the loop yourself, add ->startOfAttempt() and ->endOfAttempt() around your work so the logs are built. You can then access:

Helpers When Managing The Loop Yourself

There are the helpers you can use to help you manage the looping process.

Modelling / Simulation

If you would like to run modelling on the backoff process, you can use a Backoff instance to generate sets of delays without actually sleeping.

Equivalent methods exist to retrieve the delays in seconds, milliseconds and microseconds.

And just in case you need to check, you can retrieve the unit-of-measure being used.

A null value in the results indicates that the attempts have been exhausted.

Note: These methods will generate the same values when you call them again. Backoff maintains this state because some decorrelated backoff algorithm does this), so their values are important.

That is to say, when generating $backoff->simulate(1, 20); and then $backoff->simulate(21, 40);, the second set may be based on the first set.

To generate a new set of delays, call $backoff->reset() first.

Info: If these methods don't work fast enough for you, you could look into the DelayCalculator class, which Backoff uses behind the scenes to calculate the delays.

Generate delays with it, and then call $delayCalculator->reset() before generating a new set.

Testing This Package

Changelog

Please see CHANGELOG for more information on what has changed recently.

SemVer

This library uses SemVer 2.0.0 versioning. This means that changes to X indicate a breaking change: 0.0.X, 0.X.y, X.y.z. When this library changes to version 1.0.0, 2.0.0 and so forth, it doesn't indicate that it's necessarily a notable release, it simply indicates that the changes were breaking.

Treeware

This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.

Contributing

Please see CONTRIBUTING for details.

Code of Conduct

Please see CODE_OF_CONDUCT for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.


All versions of backoff with dependencies

PHP Build Version
Package Version
Requires php Version 8.0.* | 8.1.* | 8.2.* | 8.3.* | 8.4.*
code-distortion/di-caller Version ^0.2.1
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package code-distortion/backoff contains the following files

Loading the files please wait ....