Algori...::MILD(3pm)

๐Ÿ“ฆ
version 0.010 ยท 5 versions
, in debian trixie, ubuntu resolute, ubuntu stonking

โœจ 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 with delay=2 and you log failure() again immediately after the previous failure() (same timestamp). Then failure() returns roughly 2+2 = 4 seconds. But if you actually waited 2 seconds before calling failure() again (timestamp is 2 seconds bigger than the last one), failure() returns 2 seconds. And if you waited 4 seconds or more, failure() returns 0. โฑ๏ธ
  • 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 than 0, the actual delay ends up somewhere between a random number in original_delay * (1-jitter_factor) and original_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 (0 means 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 of initial_delay=3 and max_attempts=10, the delays go 3, 6, 12, 24, .... If failures get logged according to those suggested delays and max_actual_duration is 21 seconds, then the third failure() returns -1 instead of 24, because 3+6+12 >= 21 โ€” even though max_attempts hasn't been hit yet. ๐Ÿ˜ฎ
  • max_attempts => uint (default: 0) โ€” Maximum number of consecutive failures before giving up. 0 means retry endlessly and never ever give up. 1 means give up after a single failure (so, no retries at all). 2 means retry once after a failure. And important: after a success, the attempt count resets (as you'd expect). So if max_attempts is 3 and 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 for min_delay too. 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::LILD
  • Algorithm::Backoff::LIMD
  • Algorithm::Backoff::MIMD
  • Algorithm::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. ๐Ÿ›


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