Algorithm-Backoff

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


SYNOPSIS
     # 1. pick a strategy and instantiate

     use Algorithm::Backoff::Constant;
     my $ab = Algorithm::Backoff::Constant->new(
         delay             => 2, # required
         #delay_on_success => 0, # optional, default 0
     );

     # 2. log success/failure and get a new number of seconds to delay. if you don't
     # want to log for the current time, you can pass a timestamp (number of seconds
     # passed since some reference value, like a Unix epoch) as the argument, which
     # should be monotonically increasing.

     my $secs = $ab->failure(); # => 2
     my $secs = $ab->success(); # => 0
     my $secs = $ab->failure(); # => 2

DESCRIPTION
    This distribution provides several classes that implement various
    backoff strategies for setting delay between retry attempts.

    This class ("Algorithm::Backoff") is a base class only.

    Algorithm::Backoff does not actually provide a function/method to retry
    a piece of code. It only contains the backoff strategies and splits the
    actual delaying to another module (e.g. Retry::Backoff). This allows for

README  view on Meta::CPAN

        If you set this to a value larger than 0, the actual delay will be
        between a random number between original_delay * (1-jitter_factor)
        and original_delay * (1+jitter_factor). Jitters are usually added to
        avoid so-called "thundering herd" problem.

        The jitter will be applied to delay on failure as well as on
        success.

    *   max_attempts => *uint* (default: 0)

        Maximum number consecutive failures before giving up.

        0 means to retry endlessly without ever giving up. 1 means to give
        up after a single failure (i.e. no retry attempts). 2 means to retry
        once after a failure. Note that after a success, the number of
        attempts is reset (as expected). So if max_attempts is 3, and if you
        fail twice then succeed, then on the next failure the algorithm will
        retry again for a maximum of 3 times.

    Return value: (obj)

  success
    Usage:

     my $secs = $obj->success([ $timestamp ]);

    Log a successful attempt. If not specified, $timestamp defaults to
    current Unix timestamp. Will return the suggested number of seconds to
    wait before doing another attempt.

  failure
    Usage:

     my $secs = $obj->failure([ $timestamp ]);

    Log a failed attempt. If not specified, $timestamp defaults to current
    Unix timestamp. Will return the suggested number of seconds to wait
    before doing another attempt, or -1 if it suggests that one gives up
    (e.g. if "max_attempts" parameter has been exceeded).

HOMEPAGE
    Please visit the project's homepage at
    <https://metacpan.org/release/Algorithm-Backoff>.

SOURCE
    Source repository is at
    <https://github.com/perlancar/perl-Algorithm-Backoff>.

lib/Algorithm/Backoff.pm  view on Meta::CPAN

    consider_actual_delay => {
        summary => 'Whether to consider actual delay',
        schema => ['bool*'],
        default => 0,
        tags => ['common'],
        description => <<'_',

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

_
    },
);

our %attr_max_actual_duration = (
    max_actual_duration => {
        summary => 'Maximum number of seconds for all of the attempts (0 means unlimited)',
        schema => ['ufloat*'],
        default => 0,
        tags => ['common'],
        description => <<'_',

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

_
    },
);

our %attr_max_attempts = (
    max_attempts => {
        summary => 'Maximum number consecutive failures before giving up',
        schema => 'uint*',
        default => 0,
        tags => ['common'],
        description => <<'_',

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

lib/Algorithm/Backoff.pm  view on Meta::CPAN

herd" problem.

The jitter will be applied to delay on failure as well as on success.

_
    },
);

our %attr_delay_on_success = (
    delay_on_success => {
        summary => 'Number of seconds to wait after a success',
        schema => 'ufloat*',
        default => 0,
    },
);

our %attr_max_delay = (
    max_delay => {
        summary => 'Maximum delay time, in seconds',
        schema => 'ufloat*',
         tags => ['common'],
   },
);

our %attr_min_delay = (
    min_delay => {
        summary => 'Maximum delay time, in seconds',
        schema => 'ufloat*',
        default => 0,
        tags => ['common'],
   },
);

our %attr_initial_delay = (
    initial_delay => {
        summary => 'Initial delay for the first attempt after failure, '.
            'in seconds',
        schema => 'ufloat*',
        req => 1,
    },
);

our %attr_delay_multiple_on_failure = (
    delay_multiple_on_failure => {
        summary => 'How much to multiple previous delay, upon failure (e.g. 1.5)',
        schema => 'ufloat*',
        req => 1,

lib/Algorithm/Backoff.pm  view on Meta::CPAN

our %attr_delay_multiple_on_success = (
    delay_multiple_on_success => {
        summary => 'How much to multiple previous delay, upon success (e.g. 0.5)',
        schema => 'ufloat*',
        req => 1,
   },
);

our %attr_delay_increment_on_failure = (
    delay_increment_on_failure => {
        summary => 'How much to add to previous delay, in seconds, upon failure (e.g. 5)',
        schema => 'float*',
        req => 1,
   },
);

our %attr_delay_increment_on_success = (
    delay_increment_on_success => {
        summary => 'How much to add to previous delay, in seconds, upon success (e.g. -5)',
        schema => 'float*',
        req => 1,
   },
);

$SPEC{new} = {
    v => 1.1,
    is_class_meth => 1,
    is_func => 0,
    args => {

lib/Algorithm/Backoff.pm  view on Meta::CPAN

=head1 SYNOPSIS

 # 1. pick a strategy and instantiate

 use Algorithm::Backoff::Constant;
 my $ab = Algorithm::Backoff::Constant->new(
     delay             => 2, # required
     #delay_on_success => 0, # optional, default 0
 );

 # 2. log success/failure and get a new number of seconds to delay. if you don't
 # want to log for the current time, you can pass a timestamp (number of seconds
 # passed since some reference value, like a Unix epoch) as the argument, which
 # should be monotonically increasing.

 my $secs = $ab->failure(); # => 2
 my $secs = $ab->success(); # => 0
 my $secs = $ab->failure(); # => 2

=head1 DESCRIPTION

This distribution provides several classes that implement various backoff
strategies for setting delay between retry attempts.

This class (C<Algorithm::Backoff>) is a base class only.

Algorithm::Backoff does not actually provide a function/method to retry a piece
of code. It only contains the backoff strategies and splits the actual delaying

lib/Algorithm/Backoff.pm  view on Meta::CPAN


If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.


=back

Return value:  (obj)


=head2 success

Usage:

 my $secs = $obj->success([ $timestamp ]);

Log a successful attempt. If not specified, C<$timestamp> defaults to current
Unix timestamp. Will return the suggested number of seconds to wait before doing
another attempt.

=head2 failure

Usage:

 my $secs = $obj->failure([ $timestamp ]);

Log a failed attempt. If not specified, C<$timestamp> defaults to current Unix
timestamp. Will return the suggested number of seconds to wait before doing
another attempt, or -1 if it suggests that one gives up (e.g. if C<max_attempts>
parameter has been exceeded).

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-Algorithm-Backoff>.

lib/Algorithm/Backoff/Constant.pm  view on Meta::CPAN

    is_func => 0,
    args => {
        %Algorithm::Backoff::attr_consider_actual_delay,
        %Algorithm::Backoff::attr_max_actual_duration,
        %Algorithm::Backoff::attr_max_attempts,
        %Algorithm::Backoff::attr_jitter_factor,
        %Algorithm::Backoff::attr_delay_on_success,
        %Algorithm::Backoff::attr_min_delay,
        %Algorithm::Backoff::attr_max_delay,
        delay => {
            summary => 'Number of seconds to wait after a failure',
            schema => 'ufloat*',
            req => 1,
        },
    },
    result_naked => 1,
    result => {
        schema => 'obj*',
    },
};

lib/Algorithm/Backoff/Constant.pm  view on Meta::CPAN


 my $ab = Algorithm::Backoff::Constant->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, # optional, set to positive value to add randomness
     delay                  => 2, # required
     #delay_on_success      => 0, # optional, default 0
 );

 # 2. log success/failure and get a new number of seconds to delay, timestamp is
 # optional argument (default is current time) but must be monotonically
 # increasing.

 my $secs = $ab->failure(1554652553); # => 2
 my $secs = $ab->success();           # => 0
 my $secs = $ab->failure();           # => 2

Illustration using CLI L<show-backoff-delays> (5 failures followed by 3
successes):

 % show-backoff-delays -a Constant --delay 2 \
     0 0 0 0 0   1 1 1
 2
 2
 2
 2
 2
 0
 0
 0

=head1 DESCRIPTION

This backoff strategy is one of the simplest: it waits X second(s) after each
failure, or Y second(s) (default 0) after a success. There are limits on the
number of attempts (`max_attempts`) and total duration (`max_actual_duration`).
Some randomness can be introduced to avoid "thundering herd problem".

=head1 METHODS


=head2 new

Usage:

lib/Algorithm/Backoff/Constant.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay>* => I<ufloat>

Number of seconds to wait after a failure.

=item * B<delay_on_success> => I<ufloat> (default: 0)

Number of seconds to wait after a success.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/Exponential.pm  view on Meta::CPAN

     #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
     initial_delay          => 5, # required
     #max_delay             => 100, # optional
     #exponent_base         => 2, # optional, default 2 (binary exponentiation)
     #delay_on_success      => 0, # optional, default 0
 );

 # 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=5, max_delay=100:

 my $secs;
 $secs = $ab->failure();   # =>  5 (= initial_delay)
 $secs = $ab->failure();   # => 10 (5 * 2^1)
 $secs = $ab->failure();   # => 20 (5 * 2^2)
 $secs = $ab->failure();   # => 33 (5 * 2^3 - 7)
 $secs = $ab->failure();   # => 80 (5 * 2^4)
 $secs = $ab->failure();   # => 100 ( min(5 * 2^5, 100) )
 $secs = $ab->success();   # => 0 (= delay_on_success)

Illustration using CLI L<show-backoff-delays> (10 failures followed by 3
successes):

 % show-backoff-delays -a Exponential --initial-delay 1 --max-delay 200 \
     0 0 0 0 0   0 0 0 0 0   1 1 1
 1
 2
 4
 8

lib/Algorithm/Backoff/Exponential.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_on_success> => I<ufloat> (default: 0)

Number of seconds to wait after a success.

=item * B<exponent_base> => I<ufloat> (default: 2)

(No description)

=item * B<initial_delay>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/Fibonacci.pm  view on Meta::CPAN

    args => {
        %Algorithm::Backoff::attr_consider_actual_delay,
        %Algorithm::Backoff::attr_max_actual_duration,
        %Algorithm::Backoff::attr_max_attempts,
        %Algorithm::Backoff::attr_jitter_factor,
        %Algorithm::Backoff::attr_delay_on_success,
        %Algorithm::Backoff::attr_min_delay,
        %Algorithm::Backoff::attr_max_delay,
        initial_delay1 => {
            summary => 'Initial delay for the first attempt after failure, '.
                'in seconds',
            schema => 'ufloat*',
            req => 1,
        },
        initial_delay2 => {
            summary => 'Initial delay for the second attempt after failure, '.
                'in seconds',
            schema => 'ufloat*',
            req => 1,
        },
    },
    result_naked => 1,
    result => {
        schema => 'obj*',
    },
};

lib/Algorithm/Backoff/Fibonacci.pm  view on Meta::CPAN

     #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
     initial_delay1         => 2, # required
     initial_delay2         => 3, # required
     #max_delay             => 20, # optional
     #delay_on_success      => 0, # optional, default 0
 );

 # 2. log success/failure and get a new number of seconds to delay, timestamp is
 # optional but must be monotonically increasing.

 my $secs;
 $secs = $ab->failure();   # =>  2 (= initial_delay1)
 $secs = $ab->failure();   # =>  3 (= initial_delay2)
 $secs = $ab->failure();   # =>  5 (= 2+3)
 $secs = $ab->failure();   # =>  8 (= 3+5)
 sleep 1;
 $secs = $ab->failure();   # => 12 (= 5+8 -1)
 $secs = $ab->failure();   # => 20 (= min(13+8, 20) = max_delay)

 $secs = $ab->success();   # =>  0 (= delay_on_success)

Illustration using CLI L<show-backoff-delays> (10 failures followed by 3
successes):

 % show-backoff-delays -a Fibonacci --initial-delay1 0 --initial-delay2 1 \
     0 0 0 0 0   0 0 0 0 0   1 1 1
 0
 1
 1
 2

lib/Algorithm/Backoff/Fibonacci.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_on_success> => I<ufloat> (default: 0)

Number of seconds to wait after a success.

=item * B<initial_delay1>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<initial_delay2>* => I<ufloat>

Initial delay for the second attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/LILD.pm  view on Meta::CPAN

     #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              => 1, # optional, default 0
     #max_delay             => 100, # optional
     initial_delay              =>  3, # required
     delay_increment_on_failure =>  4, # required
     delay_increment_on_success => -5, # required
 );

 # 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=3,
 # delay_increment_on_failure=4, delay_increment_on_success=-5, min_delay=1:

 my $secs;
 $secs = $ab->failure();   # => 3  (= initial_delay)
 $secs = $ab->failure();   # => 7  (3 + 4)
 $secs = $ab->failure();   # => 11 (7 + 4)
 $secs = $ab->success();   # => 6  (11 - 5)
 $secs = $ab->success();   # => 1  (6 - 5)
 $secs = $ab->success();   # => 1  (max(1 - 5, 0, min_delay=1))
 $secs = $ab->failure();   # => 5  (1 + 4)

Illustration using CLI L<show-backoff-delays> (3 failures followed by 4
successes, followed by 3 failures):

 % show-backoff-delays -a LILD --initial-delay 3 --min-delay 1 \
     --delay-increment-on-failure 4 --delay-increment-on-success -5 \
     0 0 0   1 1 1 1  0 0 0
 3
 7
 11

lib/Algorithm/Backoff/LILD.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_increment_on_failure>* => I<float>

How much to add to previous delay, in seconds, upon failure (e.g. 5).

=item * B<delay_increment_on_success>* => I<float>

How much to add to previous delay, in seconds, upon success (e.g. -5).

=item * B<initial_delay>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/LIMD.pm  view on Meta::CPAN

     #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              => 1, # optional, default 0
     #max_delay             => 100, # optional
     initial_delay              => 2,   # required
     delay_increment_on_failure => 4,   # required
     delay_multiple_on_success  => 0.2, # required
 );

 # 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=2,
 # delay_increment_on_failure=4, delay_multiple_on_success=0.2, min_delay=1:

 my $secs;
 $secs = $ab->failure();   # =>  2   (= initial_delay)
 $secs = $ab->failure();   # =>  6   (2 + 4)
 $secs = $ab->failure();   # => 10   (2 + 4)
 $secs = $ab->success();   # =>  2   (10 * 0.2)
 $secs = $ab->success();   # =>  1   (max(2 * 0.2, 1))
 $secs = $ab->failure();   # =>  5   (1 + 4)

Illustration using CLI L<show-backoff-delays> (3 failures followed by 3
successes, followed by 3 failures):

 % show-backoff-delays -a LILD --initial-delay 2 --min-delay 1 \
     --delay-increment-on-failure 4 --delay-multiple-on-success 0.2 \
     0 0 0   1 1 1   0 0 0
 2
 6
 10

lib/Algorithm/Backoff/LIMD.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_increment_on_failure>* => I<float>

How much to add to previous delay, in seconds, upon failure (e.g. 5).

=item * B<delay_multiple_on_success>* => I<ufloat>

How much to multiple previous delay, upon success (e.g. 0.5).

=item * B<initial_delay>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/MILD.pm  view on Meta::CPAN

     #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
 );

 # 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)

Illustration using CLI L<show-backoff-delays> (4 failures followed by 5
successes, followed by 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

lib/Algorithm/Backoff/MILD.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_increment_on_success>* => I<float>

How much to add to previous delay, in seconds, upon success (e.g. -5).

=item * B<delay_multiple_on_failure>* => I<ufloat>

How much to multiple previous delay, upon failure (e.g. 1.5).

=item * B<initial_delay>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

lib/Algorithm/Backoff/MIMD.pm  view on Meta::CPAN

     #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              => 3,   # required
     delay_multiple_on_failure  => 2,   # required
     delay_multiple_on_success  => 0.5, # required
 );

 # 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=3,
 # delay_multiple_on_failure=2, delay_multiple_on_success=0.5, min_delay=2:

 my $secs;
 $secs = $ab->failure();   # => 3    (= initial_delay)
 $secs = $ab->failure();   # => 6    (3 * 2)
 $secs = $ab->failure();   # => 12   (6 * 2)
 $secs = $ab->success();   # => 6    (12 * 0.5)
 $secs = $ab->success();   # => 3    (6 * 0.5)
 $secs = $ab->success();   # => 2    (max(3*0.5, min_delay=2))
 $secs = $ab->failure();   # => 4    (2 * 2)

Illustration using CLI L<show-backoff-delays> (4 failures followed by 5
successes, followed by 3 failures):

 % show-backoff-delays -a MIMD --initial-delay 3 --min-delay 2 \
     --delay-multiple-on-failure 2 --delay-multiple-on-success 0.5 \
     0 0 0 0   1 1 1 1 1   0 0 0
 3
 6
 12

lib/Algorithm/Backoff/MIMD.pm  view on Meta::CPAN


=over 4

=item * B<consider_actual_delay> => I<bool> (default: 0)

Whether to consider actual delay.

If set to true, will take into account the actual delay (timestamp difference).
For example, when using the Constant strategy of delay=2, you log failure()
again right after the previous failure() (i.e. specify the same timestamp).
failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
seconds before calling failure() again (i.e. specify the timestamp that is 2
seconds larger than the previous timestamp), failure() will return 2 seconds.
And if you waited 4 seconds or more, failure() will return 0.

=item * B<delay_multiple_on_failure>* => I<ufloat>

How much to multiple previous delay, upon failure (e.g. 1.5).

=item * B<delay_multiple_on_success>* => I<ufloat>

How much to multiple previous delay, upon success (e.g. 0.5).

=item * B<initial_delay>* => I<ufloat>

Initial delay for the first attempt after failure, in seconds.

=item * B<jitter_factor> => I<float>

How much to add randomness.

If you set this to a value larger than 0, the actual delay will be between a
random number between original_delay * (1-jitter_factor) and original_delay *
(1+jitter_factor). Jitters are usually added to avoid so-called "thundering
herd" problem.

The jitter will be applied to delay on failure as well as on success.

=item * B<max_actual_duration> => I<ufloat> (default: 0)

Maximum number of seconds for all of the attempts (0 means unlimited).

If set to a positive number, will limit the number of seconds for all of the
attempts. This setting is used to limit the amount of time you are willing to
spend on a task. For example, when using the Exponential strategy of
initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
failures are logged according to the suggested delays, and max_actual_duration
is set to 21 seconds, then the third failure() will return -1 instead of 24
because 3+6+12 >= 21, even though max_attempts has not been exceeded.

=item * B<max_attempts> => I<uint> (default: 0)

Maximum number consecutive failures before giving up.

0 means to retry endlessly without ever giving up. 1 means to give up after a
single failure (i.e. no retry attempts). 2 means to retry once after a failure.
Note that after a success, the number of attempts is reset (as expected). So if
max_attempts is 3, and if you fail twice then succeed, then on the next failure
the algorithm will retry again for a maximum of 3 times.

=item * B<max_delay> => I<ufloat>

Maximum delay time, in seconds.

=item * B<min_delay> => I<ufloat> (default: 0)

Maximum delay time, in seconds.


=back

Return value:  (obj)

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.

t/01-base.t  view on Meta::CPAN

        consider_actual_delay => 1,
        delay => 2,
        max_attempts => 0,
    );

    is($ar->failure(1), 2);

    # we didn't wait, so the delay is now 2+2 = 4
    is($ar->failure(1), 4);

    # we now waited for 5 seconds, so delay is now 2-1 = 1
    is($ar->failure(6), 1);

    # we now waited for 2 seconds, so delay is now 2-1 = 1
    is($ar->failure(8), 1);

    # we now waited for 3 seconds, so delay is now 2-2 = 0
    is($ar->failure(11), 0);
};

# This tests that consider_actual_delay uses the post-processed _prev_delay
# value correctly.
subtest "attr: consider_actual_delay + post-processing" => sub {
    my $ar;

    $ar = Algorithm::Backoff::Constant->new(
        consider_actual_delay => 1,
        delay     => 3,  # "pre-processor" delay
        max_delay => 2,  # real delay
        max_attempts => 0,
    );

    # first failure after 1 second
    is($ar->failure(1), 2);

    # 2s delay + instant failure, so the delay is now 3 -> max 2
    is($ar->failure(1+2+0), 2);

    # 2s delay + 2s failure, so the delay is now 3-2 = 1
    is($ar->failure(3+2+2), 1);

    # 1s delay + 5s failure, so delay is now 3-5 = -2 -> min 0
    is($ar->failure(7+1+5), 0);



( run in 1.188 second using v1.01-cache-2.11-cpan-39bf76dae61 )