Algori...::MILD(3pm)
โจ Algorithm::Backoff::MILD ๐ โ Multiplicative Increment, Linear Decrement (MILD) backoff โจ
okay so bestie, picture this: something fails, you back off, but you back off multiplicatively on the way up and linearly on the way down. That's MILD. It's giving "graceful recovery arc" energy and honestly? obsessed. ๐ฆ
๐ธ VERSION ๐ธ
This doc is for version 0.010 of Algorithm::Backoff::MILD, which ships in the Perl distribution Algorithm-Backoff, and it was released on 2024-02-24. ๐
โจ SYNOPSIS โจ
First things first, you use it:
use Algorithm::Backoff::MILD;
# 1. instantiate
my $ab = Algorithm::Backoff::MILD->new(
#consider_actual_delay => 1, # optional, default 0
#max_actual_duration => 0, # optional, default 0 (retry endlessly)
#max_attempts => 0, # optional, default 0 (retry endlessly)
#jitter_factor => 0.25, # optional, default 0
#min_delay => 2, # optional, default 0
#max_delay => 100, # optional
initial_delay => 1, # required
delay_multiple_on_failure => 1.5, # required
delay_increment_on_success => -2, # required
);
Then step 2: you log successes and failures, and it hands you back a fresh number of seconds to wait. The timestamp is optional but it must be monotonically increasing โ no time-traveling, bestie. โณ
# 2. log success/failure and get a new number of seconds to delay, timestamp is
# optional but must be monotonically increasing.
# for example, using the parameters initial_delay=1,
# delay_multiple_on_failure=1.5, delay_increment_on_success=-2, min_delay=0.5:
my $secs;
$secs = $ab->failure(); # => 1 (= initial_delay)
$secs = $ab->failure(); # => 1.5 (1 * 1.5)
$secs = $ab->failure(); # => 2.25 (1.5 * 1.5)
$secs = $ab->success(); # => 0.25 (2.25 - 2)
$secs = $ab->success(); # => 1 (max(0.25 - 2, 0.5, 1))
$secs = $ab->failure(); # => 1.5 (1 * 1.5)
And here's a whole vibe check via the CLI tool show-backoff-delays โ 4 failures, then 5 successes, then 3 failures:
% show-backoff-delays -a MILD --initial-delay 3 --min-delay 1 \
--delay-multiple-on-failure 2 --delay-increment-on-success -5 \
0 0 0 0 1 1 1 1 1 0 0 0
3
6
12
24
19
14
9
4
1
2
4
look at those numbers go up and come back down. character development, fr fr. ๐๐
๐ DESCRIPTION ๐
So when a thing fails, the next delay gets calculated like this:
D1 = initial_delay
D2 = max(min(D1 * delay_multiple_on_failure, max_delay), min_delay)
...
And when a thing succeeds, the next delay goes:
D1 = initial_delay
D2 = max(D1 + delay_increment_on_success, min_delay, initial_delay)
...
The three that are absolutely required: initial_delay, delay_multiple_on_failure, and delay_increment_on_success. And heads up โ initial_delay and min_delay should be larger than zero, because otherwise every future delay is just gonna be zero. Not the slay you think it is. ๐ญ
There are also caps on how much you're willing to try: a limit on the number of attempts (max_attempts) and a limit on total duration (max_actual_duration).
๐ก Pro tip from the docs: add a jitter factor, like 0.25, to sprinkle in some randomness โ it helps dodge the whole "thundering herd problem". ๐๐๐
๐ METHODS ๐
new
Usage:
new(%args) -> obj
Quick note: this function is not exported. You call it the OO way.
Arguments โ and the * means required, no skipping:
consider_actual_delay=> bool (default:0) โ Whether to consider actual delay. If you set this to true, it takes the actual delay (the timestamp difference) into account. Like, say you're on the Constant strategy withdelay=2and you logfailure()again immediately after the previousfailure()(same timestamp). Thenfailure()returns roughly2+2 = 4seconds. But if you actually waited 2 seconds before callingfailure()again (timestamp is 2 seconds bigger than the last one),failure()returns2seconds. And if you waited 4 seconds or more,failure()returns0. โฑ๏ธdelay_increment_on_success*=> float โ How much to add to the previous delay, in seconds, upon success (e.g.-5). (Yes, it's a negative number in the examples โ we're shrinking the delay. That's the whole point. ๐ )delay_multiple_on_failure*=> ufloat โ How much to multiply the previous delay by, upon failure (e.g.1.5).initial_delay*=> ufloat โ The initial delay for the first attempt after failure, in seconds. This is your starting point, your origin story. โญjitter_factor=> float โ How much randomness to add. If you set this bigger than0, the actual delay ends up somewhere between a random number inoriginal_delay * (1-jitter_factor)andoriginal_delay * (1+jitter_factor). Jitters get added usually to avoid the so-called "thundering herd" problem. And yes, the jitter hits the delay on failure and on success. Equal opportunity randomness. ๐max_actual_duration=> ufloat (default:0) โ Maximum number of seconds for all of the attempts (0means unlimited). Set it to a positive number and it caps the total seconds across all attempts. This is how you limit how much time you're willing to throw at a task. Example: with the Exponential strategy ofinitial_delay=3andmax_attempts=10, the delays go3, 6, 12, 24, .... If failures get logged according to those suggested delays andmax_actual_durationis21seconds, then the thirdfailure()returns-1instead of24, because3+6+12 >= 21โ even thoughmax_attemptshasn't been hit yet. ๐ฎmax_attempts=> uint (default:0) โ Maximum number of consecutive failures before giving up.0means retry endlessly and never ever give up.1means give up after a single failure (so, no retries at all).2means retry once after a failure. And important: after a success, the attempt count resets (as you'd expect). So ifmax_attemptsis3and you fail twice and then succeed, the next failure will start the retry budget over again for a max of 3 times. ๐max_delay=> ufloat โ Maximum delay time, in seconds.min_delay=> ufloat (default:0) โ Maximum delay time, in seconds. (Yep, that is literally what the doc says here formin_delaytoo. I'm just the messenger ๐ โ copy-paste energy is iconic in its own way.)
Return value: (obj) โ you get an object back, go wild. ๐ซถ
๐ฆ HOMEPAGE ๐ฆ
Wanna come hang out at the project's homepage? It's at <https://metacpan.org/release/Algorithm-Backoff>. ๐
๐ฅ SOURCE ๐ฅ
The source repository lives at <https://github.com/perlancar/perl-Algorithm-Backoff>. Go peek, it's free. ๐
๐ SEE ALSO ๐
Algorithm::Backoff::LILDAlgorithm::Backoff::LIMDAlgorithm::Backoff::MIMDAlgorithm::Backoff- Other
"Algorithm::Backoff::*"classes.
(the whole backoff family is serving looks, iykyk โจ)
๐ AUTHOR ๐
perlancar <perlancar@cpan.org> โ the icon, the moment. ๐
๐ CONTRIBUTING ๐
Wanna help out? You can send patches by email / via RT, or send pull requests on GitHub. Easy.
Most of the time you do not need to build the distribution yourself. You can just modify the code, then test it like:
% prove -l
If you do wanna build the distribution (say, to try installing it locally on your system), you can install Dist::Zilla, Dist::Zilla::PluginBundle::Author::PERLANCAR, Pod::Weaver::PluginBundle::Author::PERLANCAR, and sometimes one or two other Dist::Zilla- and/or Pod::Weaver plugins. Any extra steps required beyond that are considered a bug and you should report them. ๐
๐ COPYRIGHT AND LICENSE ๐
This software is copyright (c) 2024, 2019 by perlancar <perlancar@cpan.org>.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. ๐ซถ
๐ BUGS ๐
Please report any bugs or feature requests on the bugtracker website: <https://rt.cpan.org/Public/Dist/Display.html?Name=Algorithm-Backoff>.
When you submit a bug or a request, pls pls pls include a test-file or a patch to an existing test-file that shows off the bug or the feature you want. Receipts, bestie. ๐
and that's the whole page, no cap. this was Algorithm::Backoff::MILD from Perl distribution Algorithm-Backoff, documented under perl v5.40.1, dated 2025-05-04. go forth and back off gracefully. mwah. ๐โจ
๐ฆ where this page comes from
- debian trixie: libalgorithm-backoff-perl 0.010-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libalgorithm-backoff-perl 0.010-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libalgorithm-backoff-perl 0.010-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms