File Coverage

blib/lib/Algorithm/Backoff/Fibonacci.pm
Criterion Covered Total %
statement 21 21 100.0
branch 4 4 100.0
condition n/a
subroutine 5 5 100.0
pod n/a
total 30 30 100.0


line stmt bran cond sub pod time code
1             package Algorithm::Backoff::Fibonacci;
2              
3 2     2   483347 use strict;
  2         3  
  2         70  
4 2     2   10 use warnings;
  2         23  
  2         121  
5              
6 2     2   470 use parent qw(Algorithm::Backoff);
  2         339  
  2         14  
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_delay_on_success,
25             %Algorithm::Backoff::attr_min_delay,
26             %Algorithm::Backoff::attr_max_delay,
27             initial_delay1 => {
28             summary => 'Initial delay for the first attempt after failure, '.
29             'in seconds',
30             schema => 'ufloat*',
31             req => 1,
32             },
33             initial_delay2 => {
34             summary => 'Initial delay for the second attempt after failure, '.
35             'in seconds',
36             schema => 'ufloat*',
37             req => 1,
38             },
39             },
40             result_naked => 1,
41             result => {
42             schema => 'obj*',
43             },
44             };
45              
46             sub _success {
47 1     1   4 my ($self, $timestamp) = @_;
48 1         3 $self->{delay_on_success};
49             }
50              
51             sub _failure {
52 6     6   14 my ($self, $timestamp) = @_;
53 6 100       22 if ($self->{_attempts} == 1) {
    100          
54 1         3 $self->{_delay_n_min_1} = 0;
55 1         5 $self->{_delay_n} = $self->{initial_delay1};
56             } elsif ($self->{_attempts} == 2) {
57 1         3 $self->{_delay_n_min_1} = $self->{initial_delay1};
58 1         11 $self->{_delay_n} = $self->{initial_delay2};
59             } else {
60 4         8 my $tmp = $self->{_delay_n};
61 4         11 $self->{_delay_n} = $self->{_delay_n_min_1} + $self->{_delay_n};
62 4         8 $self->{_delay_n_min_1} = $tmp;
63 4         13 $self->{_delay_n};
64             }
65             }
66              
67             1;
68             # ABSTRACT: Backoff using Fibonacci sequence
69              
70             __END__
71              
72             =pod
73              
74             =encoding UTF-8
75              
76             =head1 NAME
77              
78             Algorithm::Backoff::Fibonacci - Backoff using Fibonacci sequence
79              
80             =head1 VERSION
81              
82             This document describes version 0.010 of Algorithm::Backoff::Fibonacci (from Perl distribution Algorithm-Backoff), released on 2024-02-24.
83              
84             =head1 SYNOPSIS
85              
86             use Algorithm::Backoff::Fibonacci;
87              
88             # 1. instantiate
89              
90             my $ab = Algorithm::Backoff::Fibonacci->new(
91             #consider_actual_delay => 1, # optional, default 0
92             #max_actual_duration => 0, # optional, default 0 (retry endlessly)
93             #max_attempts => 0, # optional, default 0 (retry endlessly)
94             #jitter_factor => 0.25, # optional, default 0
95             initial_delay1 => 2, # required
96             initial_delay2 => 3, # required
97             #max_delay => 20, # optional
98             #delay_on_success => 0, # optional, default 0
99             );
100              
101             # 2. log success/failure and get a new number of seconds to delay, timestamp is
102             # optional but must be monotonically increasing.
103              
104             my $secs;
105             $secs = $ab->failure(); # => 2 (= initial_delay1)
106             $secs = $ab->failure(); # => 3 (= initial_delay2)
107             $secs = $ab->failure(); # => 5 (= 2+3)
108             $secs = $ab->failure(); # => 8 (= 3+5)
109             sleep 1;
110             $secs = $ab->failure(); # => 12 (= 5+8 -1)
111             $secs = $ab->failure(); # => 20 (= min(13+8, 20) = max_delay)
112              
113             $secs = $ab->success(); # => 0 (= delay_on_success)
114              
115             Illustration using CLI L<show-backoff-delays> (10 failures followed by 3
116             successes):
117              
118             % show-backoff-delays -a Fibonacci --initial-delay1 0 --initial-delay2 1 \
119             0 0 0 0 0 0 0 0 0 0 1 1 1
120             0
121             1
122             1
123             2
124             3
125             5
126             8
127             13
128             21
129             34
130             0
131             0
132             0
133              
134             =head1 DESCRIPTION
135              
136             This backoff algorithm calculates the next delay using Fibonacci sequence. For
137             example, if the two initial numbers are 2 and 3:
138              
139             2, 3, 5, 8, 13, 21, ...
140              
141             C<initial_delay1> and C<initial_delay2> are required. The other attributes are
142             optional.
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_on_success> => I<ufloat> (default: 0)
178              
179             Number of seconds to wait after a success.
180              
181             =item * B<initial_delay1>* => I<ufloat>
182              
183             Initial delay for the first attempt after failure, in seconds.
184              
185             =item * B<initial_delay2>* => I<ufloat>
186              
187             Initial delay for the second 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<https://en.wikipedia.org/wiki/Fibonacci_number>
246              
247             L<Algorithm::Backoff>
248              
249             Other C<Algorithm::Backoff::*> classes.
250              
251             =head1 AUTHOR
252              
253             perlancar <perlancar@cpan.org>
254              
255             =head1 CONTRIBUTING
256              
257              
258             To contribute, you can send patches by email/via RT, or send pull requests on
259             GitHub.
260              
261             Most of the time, you don't need to build the distribution yourself. You can
262             simply modify the code, then test via:
263              
264             % prove -l
265              
266             If you want to build the distribution (e.g. to try to install it locally on your
267             system), you can install L<Dist::Zilla>,
268             L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
269             L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
270             Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
271             that are considered a bug and can be reported to me.
272              
273             =head1 COPYRIGHT AND LICENSE
274              
275             This software is copyright (c) 2024, 2019 by perlancar <perlancar@cpan.org>.
276              
277             This is free software; you can redistribute it and/or modify it under
278             the same terms as the Perl 5 programming language system itself.
279              
280             =head1 BUGS
281              
282             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Algorithm-Backoff>
283              
284             When submitting a bug or request, please include a test-file or a
285             patch to an existing test-file that illustrates the bug or desired
286             feature.
287              
288             =cut