Algorithm-Backoff-RetryTimeouts
view release on metacpan or search on metacpan
1234567891011Changelog
for
Algorithm-Backoff-RetryTimeouts
v1.0.0 2021-02-11T22:07:03
- Fix POD error (Brendan Byrd)
- Create distribution files (Andrew Hewus Fresh)
- Set _attempts / _last_timestamp even on max duration/attempt failures
(Brendan Byrd)
- Fix unnecessary delays during the first failure (Brendan Byrd)
- Add timeout_jitter_factor
with
a
default
of 10% (Brendan Byrd)
- Create Algorithm::Backoff::RetryTimeouts and unit test (Brendan Byrd)
- Initial Commit (Brendan Byrd)
616263646566676869707172737475767778798081
* Exponential backoff - A
sqrt
(2) exponential delay keeps single
retries from waiting too long,
while
spreading out repeated retries
that may fail too quickly and run out of max attempts. This also
decreases the congestion that happens
with
repeated attempts.
* Jitter - Adding random jitter to the retry delays solves
for
the
Thundering Herd problem.
* Adjustable timeouts - Providing an adjustable timeout
after
each
request solves the opposite problem of exponential backoffs: slower,
unresponsive errors that gobble up all of the max duration
time
in
one go. Each new timeout is a certain percentage of the
time
left.
Typical scenario
Here's an example scenario of the algorithm
with
existing defaults:
$retry_algo
is created, and timer starts
Initial timeout is 25s
lib/Algorithm/Backoff/RetryTimeouts.pm view on Meta::CPAN
787980818283848586878889909192939495969798#pod max attempts. This also decreases the congestion that happens with repeated attempts.
#pod
#pod =item *
#pod
#pod B<Jitter> - Adding random jitter to the retry delays solves for the Thundering Herd
#pod problem.
#pod
#pod =item *
#pod
#pod B<Adjustable timeouts> - Providing an adjustable timeout after each request solves the
#pod opposite problem of exponential backoffs: slower, unresponsive errors that gobble up all
#pod of the max duration time in one go. Each new timeout is a certain percentage of the time
#pod left.
#pod
#pod =back
#pod
#pod =head2 Typical scenario
#pod
#pod Here's an example scenario of the algorithm with existing defaults:
#pod
#pod $retry_algo is created, and timer starts
lib/Algorithm/Backoff/RetryTimeouts.pm view on Meta::CPAN
443444445446447448449450451452453454455456457458459460461462463max attempts. This also decreases the congestion that happens
with
repeated attempts.
=item *
B<Jitter> - Adding random jitter to the retry delays solves for the Thundering Herd
problem.
=item *
B<Adjustable timeouts> - Providing an adjustable timeout after each request solves the
opposite problem of exponential backoffs: slower, unresponsive errors that gobble up all
of the max duration time in one go. Each new timeout is a certain percentage of the time
left.
=back
=head2 Typical scenario
Here's an example scenario of the algorithm with existing defaults:
$retry_algo is created, and timer starts
t/00-report-prereqs.t view on Meta::CPAN
7172737475767778798081828384858687888990919293949596979899100101102103my
$static_prereqs
=
do
'./t/00-report-prereqs.dd'
;
# Merge all prereqs (either with ::Prereqs or a hashref)
my
$full_prereqs
= _merge_prereqs(
(
$HAS_CPAN_META
?
$cpan_meta_pre
->new : {} ),
$static_prereqs
);
# Add dynamic prereqs to the included modules list (if we can)
my
(
$source
) =
grep
{ -f }
'MYMETA.json'
,
'MYMETA.yml'
;
my
$cpan_meta_error
;
if
(
$source
&&
$HAS_CPAN_META
&& (
my
$meta
=
eval
{ CPAN::Meta->load_file(
$source
) } )
) {
$full_prereqs
= _merge_prereqs(
$full_prereqs
,
$meta
->prereqs);
}
else
{
$cpan_meta_error
= $@;
# capture error from CPAN::Meta->load_file($source)
$source
=
'static metadata'
;
}
my
@full_reports
;
my
@dep_errors
;
my
$req_hash
=
$HAS_CPAN_META
?
$full_prereqs
->as_string_hash :
$full_prereqs
;
# Add static includes into a fake section
for
my
$mod
(
@include
) {
$req_hash
->{other}{modules}{
$mod
} = 0;
}
for
my
$phase
(
qw(configure build test runtime develop other)
) {
next
unless
$req_hash
->{
$phase
};
next
if
(
$phase
eq
'develop'
and not
$ENV
{AUTHOR_TESTING});
t/00-report-prereqs.t view on Meta::CPAN
123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
my
$req_string
=
$want
eq
'any'
?
'any version required'
:
"version '$want' required"
;
if
(
$prefix
) {
my
$have
= MM->parse_version( File::Spec->catfile(
$prefix
,
$file
) );
$have
=
"undef"
unless
defined
$have
;
push
@reports
, [
$mod
,
$want
,
$have
];
if
(
$DO_VERIFY_PREREQS
&&
$HAS_CPAN_META
&&
$type
eq
'requires'
) {
if
(
$have
!~ /\A
$lax_version_re
\z/ ) {
push
@dep_errors
,
"$mod version '$have' cannot be parsed ($req_string)"
;
}
elsif
( !
$full_prereqs
->requirements_for(
$phase
,
$type
)->accepts_module(
$mod
=>
$have
) ) {
push
@dep_errors
,
"$mod version '$have' is not in required range '$want'"
;
}
}
}
else
{
push
@reports
, [
$mod
,
$want
,
"missing"
];
if
(
$DO_VERIFY_PREREQS
&&
$type
eq
'requires'
) {
push
@dep_errors
,
"$mod is not installed ($req_string)"
;
}
}
}
if
(
@reports
) {
push
@full_reports
,
"=== $title ===\n\n"
;
my
$ml
= _max(
map
{
length
$_
->[0] }
@reports
);
my
$wl
= _max(
map
{
length
$_
->[1] }
@reports
);
my
$hl
= _max(
map
{
length
$_
->[2] }
@reports
);
t/00-report-prereqs.t view on Meta::CPAN
164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
push
@full_reports
,
"\n"
;
}
}
}
if
(
@full_reports
) {
diag
"\nVersions for all modules listed in $source (including optional ones):\n\n"
,
@full_reports
;
}
if
(
$cpan_meta_error
||
@dep_errors
) {
diag
"\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n"
;
}
if
(
$cpan_meta_error
) {
my
(
$orig_source
) =
grep
{ -f }
'MYMETA.json'
,
'MYMETA.yml'
;
diag
"\nCPAN::Meta->load_file('$orig_source') failed with: $cpan_meta_error\n"
;
}
if
(
@dep_errors
) {
diag
join
(
"\n"
,
"\nThe following REQUIRED prerequisites were not satisfied:\n"
,
@dep_errors
,
"\n"
);
}
pass;
# vim: ts=4 sts=4 sw=4 et:
( run in 0.649 second using v1.01-cache-2.11-cpan-95122f20152 )