Algorithm-Backoff-RetryTimeouts
view release on metacpan or search on metacpan
Changelog 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)
* 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
#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
max 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
my $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
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
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.676 second using v1.01-cache-2.11-cpan-65fba6d93b7 )