File Coverage

blib/lib/Algorithm/Backoff/LILD.pm
Criterion Covered Total %
statement 18 19 94.7
branch 3 4 75.0
condition n/a
subroutine 5 5 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Algorithm::Backoff::LILD;
2              
3 2     2   530568 use strict;
  2         4  
  2         95  
4 2     2   11 use warnings;
  2         4  
  2         135  
5              
6 2     2   317 use parent qw(Algorithm::Backoff);
  2         232  
  2         12  
7              
8             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
9             our $DATE = '2024-02-24'; # DATE
10             our $DIST = 'Algorithm-Backoff'; # DIST
11             our $VERSION = '0.010'; # VERSION
12              
13             our %SPEC;
14              
15             $SPEC{new} = {
16             v => 1.1,
17             is_class_meth => 1,
18             is_func => 0,
19             args => {
20             %Algorithm::Backoff::attr_consider_actual_delay,
21             %Algorithm::Backoff::attr_max_actual_duration,
22             %Algorithm::Backoff::attr_max_attempts,
23             %Algorithm::Backoff::attr_jitter_factor,
24             %Algorithm::Backoff::attr_max_delay,
25             %Algorithm::Backoff::attr_min_delay,
26             %Algorithm::Backoff::attr_initial_delay,
27             %Algorithm::Backoff::attr_delay_increment_on_failure,
28             %Algorithm::Backoff::attr_delay_increment_on_success,
29             },
30             result_naked => 1,
31             result => {
32             schema => 'obj*',
33             },
34             };
35              
36             sub _success {
37 4     4   5 my ($self, $timestamp) = @_;
38              
39 4 50       8 unless (defined $self->{_prev_delay}) {
40 0         0 return $self->{_prev_delay} = $self->{initial_delay};
41             }
42              
43 4         6 my $delay = $self->{_prev_delay} + $self->{delay_increment_on_success};
44              
45 4         5 $delay;
46             }
47              
48             sub _failure {
49 5     5   6 my ($self, $timestamp) = @_;
50              
51 5 100       10 unless (defined $self->{_prev_delay}) {
52 1         4 return $self->{_prev_delay} = $self->{initial_delay};
53             }
54              
55 4         6 my $delay = $self->{_prev_delay} + $self->{delay_increment_on_failure};
56              
57 4         8 $delay;
58             }
59              
60             1;
61             # ABSTRACT: Linear Increment, Linear Decrement (LILD) backoff
62              
63             __END__
64              
65             =pod
66              
67             =encoding UTF-8
68              
69             =head1 NAME
70              
71             Algorithm::Backoff::LILD - Linear Increment, Linear Decrement (LILD) backoff
72              
73             =head1 VERSION
74              
75             This document describes version 0.010 of Algorithm::Backoff::LILD (from Perl distribution Algorithm-Backoff), released on 2024-02-24.
76              
77             =head1 SYNOPSIS
78              
79             use Algorithm::Backoff::LILD;
80              
81             # 1. instantiate
82              
83             my $ab = Algorithm::Backoff::LILD->new(
84             #consider_actual_delay => 1, # optional, default 0
85             #max_actual_duration => 0, # optional, default 0 (retry endlessly)
86             #max_attempts => 0, # optional, default 0 (retry endlessly)
87             #jitter_factor => 0.25, # optional, default 0
88             min_delay => 1, # optional, default 0
89             #max_delay => 100, # optional
90             initial_delay => 3, # required
91             delay_increment_on_failure => 4, # required
92             delay_increment_on_success => -5, # required
93             );
94              
95             # 2. log success/failure and get a new number of seconds to delay, timestamp is
96             # optional but must be monotonically increasing.
97              
98             # for example, using the parameters initial_delay=3,
99             # delay_increment_on_failure=4, delay_increment_on_success=-5, min_delay=1:
100              
101             my $secs;
102             $secs = $ab->failure(); # => 3 (= initial_delay)
103             $secs = $ab->failure(); # => 7 (3 + 4)
104             $secs = $ab->failure(); # => 11 (7 + 4)
105             $secs = $ab->success(); # => 6 (11 - 5)
106             $secs = $ab->success(); # => 1 (6 - 5)
107             $secs = $ab->success(); # => 1 (max(1 - 5, 0, min_delay=1))
108             $secs = $ab->failure(); # => 5 (1 + 4)
109              
110             Illustration using CLI L<show-backoff-delays> (3 failures followed by 4
111             successes, followed by 3 failures):
112              
113             % show-backoff-delays -a LILD --initial-delay 3 --min-delay 1 \
114             --delay-increment-on-failure 4 --delay-increment-on-success -5 \
115             0 0 0 1 1 1 1 0 0 0
116             3
117             7
118             11
119             6
120             1
121             1
122             1
123             5
124             9
125             13
126              
127             =head1 DESCRIPTION
128              
129             Upon failure, this backoff algorithm calculates the next delay as:
130              
131             D1 = initial_delay
132             D2 = max(min(D1 + delay_increment_on_failure, max_delay), min_delay)
133             ...
134              
135             Upon success, the next delay is calculated as:
136              
137             D1 = initial_delay
138             D2 = max(D1 + delay_increment_on_success, min_delay, initial_delay)
139             ...
140              
141             C<initial_delay>, C<delay_increment_on_failure>, and
142             C<delay_increment_on_success> are required.
143              
144             There are limits on the number of attempts (`max_attempts`) and total duration
145             (`max_actual_duration`).
146              
147             It is recommended to add a jitter factor, e.g. 0.25 to add some randomness to
148             avoid "thundering herd problem".
149              
150             =head1 METHODS
151              
152              
153             =head2 new
154              
155             Usage:
156              
157             new(%args) -> obj
158              
159             This function is not exported.
160              
161             Arguments ('*' denotes required arguments):
162              
163             =over 4
164              
165             =item * B<consider_actual_delay> => I<bool> (default: 0)
166              
167             Whether to consider actual delay.
168              
169             If set to true, will take into account the actual delay (timestamp difference).
170             For example, when using the Constant strategy of delay=2, you log failure()
171             again right after the previous failure() (i.e. specify the same timestamp).
172             failure() will then return ~2+2 = 4 seconds. On the other hand, if you waited 2
173             seconds before calling failure() again (i.e. specify the timestamp that is 2
174             seconds larger than the previous timestamp), failure() will return 2 seconds.
175             And if you waited 4 seconds or more, failure() will return 0.
176              
177             =item * B<delay_increment_on_failure>* => I<float>
178              
179             How much to add to previous delay, in seconds, upon failure (e.g. 5).
180              
181             =item * B<delay_increment_on_success>* => I<float>
182              
183             How much to add to previous delay, in seconds, upon success (e.g. -5).
184              
185             =item * B<initial_delay>* => I<ufloat>
186              
187             Initial delay for the first attempt after failure, in seconds.
188              
189             =item * B<jitter_factor> => I<float>
190              
191             How much to add randomness.
192              
193             If you set this to a value larger than 0, the actual delay will be between a
194             random number between original_delay * (1-jitter_factor) and original_delay *
195             (1+jitter_factor). Jitters are usually added to avoid so-called "thundering
196             herd" problem.
197              
198             The jitter will be applied to delay on failure as well as on success.
199              
200             =item * B<max_actual_duration> => I<ufloat> (default: 0)
201              
202             Maximum number of seconds for all of the attempts (0 means unlimited).
203              
204             If set to a positive number, will limit the number of seconds for all of the
205             attempts. This setting is used to limit the amount of time you are willing to
206             spend on a task. For example, when using the Exponential strategy of
207             initial_delay=3 and max_attempts=10, the delays will be 3, 6, 12, 24, ... If
208             failures are logged according to the suggested delays, and max_actual_duration
209             is set to 21 seconds, then the third failure() will return -1 instead of 24
210             because 3+6+12 >= 21, even though max_attempts has not been exceeded.
211              
212             =item * B<max_attempts> => I<uint> (default: 0)
213              
214             Maximum number consecutive failures before giving up.
215              
216             0 means to retry endlessly without ever giving up. 1 means to give up after a
217             single failure (i.e. no retry attempts). 2 means to retry once after a failure.
218             Note that after a success, the number of attempts is reset (as expected). So if
219             max_attempts is 3, and if you fail twice then succeed, then on the next failure
220             the algorithm will retry again for a maximum of 3 times.
221              
222             =item * B<max_delay> => I<ufloat>
223              
224             Maximum delay time, in seconds.
225              
226             =item * B<min_delay> => I<ufloat> (default: 0)
227              
228             Maximum delay time, in seconds.
229              
230              
231             =back
232              
233             Return value: (obj)
234              
235             =head1 HOMEPAGE
236              
237             Please visit the project's homepage at L<https://metacpan.org/release/Algorithm-Backoff>.
238              
239             =head1 SOURCE
240              
241             Source repository is at L<https://github.com/perlancar/perl-Algorithm-Backoff>.
242              
243             =head1 SEE ALSO
244              
245             L<Algorithm::Backoff::LIMD>
246              
247             L<Algorithm::Backoff::MILD>
248              
249             L<Algorithm::Backoff::MIMD>
250              
251             L<Algorithm::Backoff>
252              
253             Other C<Algorithm::Backoff::*> classes.
254              
255             =head1 AUTHOR
256              
257             perlancar <perlancar@cpan.org>
258              
259             =head1 CONTRIBUTING
260              
261              
262             To contribute, you can send patches by email/via RT, or send pull requests on
263             GitHub.
264              
265             Most of the time, you don't need to build the distribution yourself. You can
266             simply modify the code, then test via:
267              
268             % prove -l
269              
270             If you want to build the distribution (e.g. to try to install it locally on your
271             system), you can install L<Dist::Zilla>,
272             L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
273             L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
274             Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
275             that are considered a bug and can be reported to me.
276              
277             =head1 COPYRIGHT AND LICENSE
278              
279             This software is copyright (c) 2024, 2019 by perlancar <perlancar@cpan.org>.
280              
281             This is free software; you can redistribute it and/or modify it under
282             the same terms as the Perl 5 programming language system itself.
283              
284             =head1 BUGS
285              
286             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Algorithm-Backoff>
287              
288             When submitting a bug or request, please include a test-file or a
289             patch to an existing test-file that illustrates the bug or desired
290             feature.
291              
292             =cut