Action-Retry
view release on metacpan or search on metacpan
lib/Action/Retry.pm view on Meta::CPAN
#
# This file is part of Action-Retry
#
# This software is copyright (c) 2013 by Damien "dams" Krotkine.
#
# This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#
package Action::Retry;
{
$Action::Retry::VERSION = '0.24';
}
# ABSTRACT: Module to try to perform an action, with various ways of retrying and sleeping between retries.
use Module::Runtime qw(use_module);
use Scalar::Util qw(blessed);
use Time::HiRes qw(usleep gettimeofday);
use Carp;
use base 'Exporter';
our @EXPORT_OK = qw(retry);
# export by default if run from command line
our @EXPORT = ((caller())[1] eq '-e' ? @EXPORT_OK : ());
use Moo;
has attempt_code => (
is => 'ro',
required => 1,
isa => sub { ref $_[0] eq 'CODE' },
);
has retry_if_code => (
is => 'ro',
required => 1,
isa => sub { ref $_[0] eq 'CODE' },
default => sub { sub { $_[0] }; },
);
has on_failure_code => (
is => 'ro',
isa => sub { ref $_[0] eq 'CODE' },
predicate => 1,
);
has strategy => (
is => 'ro',
default => sub { 'Constant' },
coerce => sub {
my $attr = $_[0];
blessed($attr)
and return $attr;
my $class_name = $attr;
my $constructor_params = {};
if (ref $attr eq 'HASH') {
$class_name = (keys %$attr)[0];
$constructor_params = $attr->{$class_name};
}
$class_name = $class_name =~ /^\+(.+)$/ ? $1 : "Action::Retry::Strategy::$class_name";
return use_module($class_name)->new($constructor_params);
},
isa => sub { $_[0]->does('Action::Retry::Strategy') or croak 'Should consume the Action::Retry::Strategy role' },
);
lib/Action/Retry.pm view on Meta::CPAN
@attempt_result = eval { $self->attempt_code->(@_) };
$error = $@;
} elsif ( ! defined wantarray ) {
eval { $self->attempt_code->(@_) };
$error = $@;
} else {
$attempt_result = eval { $self->attempt_code->(@_) };
$error = $@;
}
my $h = { action_retry => $self,
attempt_result => ( $wantarray ? \@attempt_result : $attempt_result ),
attempt_parameters => \@_,
};
$self->retry_if_code->($error, $h )
or $self->strategy->reset, $@ = $error, return ( $wantarray ? @attempt_result : $attempt_result );
if (! $self->strategy->needs_to_retry) {
$self->strategy->reset;
$self->has_on_failure_code
and return $self->on_failure_code->($error, $h);
return;
}
if ($self->non_blocking) {
my ($seconds, $microseconds) = gettimeofday;
$self->_needs_sleeping_until($seconds * 1000 + int($microseconds / 1000) + $self->strategy->compute_sleep_time);
} else {
usleep($self->strategy->compute_sleep_time * 1000);
$self->strategy->next_step;
}
}
}
sub retry (&;@) {
my $code = shift;
@_ % 2
and croak "arguments to retry must be a CodeRef, and an even number of key / values";
my %args = @_;
Action::Retry->new( attempt_code => $code, %args )->run();
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Action::Retry - Module to try to perform an action, with various ways of retrying and sleeping between retries.
=head1 VERSION
version 0.24
=head1 SYNOPSIS
# Simple usage, will attempt to run the code, retrying if it dies, retrying
# 10 times max, sleeping 1 second between retries
# functional interface
use Action::Retry qw(retry);
retry { do_stuff };
# OO interface
use Action::Retry;
Action::Retry->new( attempt_code => sub { do_stuff; } )->run();
# Same, but sleep time is doubling each time, and arguments passed to the
# attempted code
# OO interface
my $action = Action::Retry->new(
attempt_code => sub { my ($num, $str) = @_; ... },
strategy => 'Linear',
);
my $result = $action->run(42, "foo");
# functional interface
retry { my ($num, $str) = @_;... } strategy => 'Linear';
# Same, but sleep time is following the Fibonacci sequence
# OO interface
my $action = Action::Retry->new(
attempt_code => sub { ... },
strategy => 'Fibonacci',
);
$action->run();
# functional interface
retry { ... } strategy => 'Fibonacci';
# The code to check if the attempt succeeded can be customized. Strategies
# can take arguments. Code on failure can be specified.
# OO way
my $action = Action::Retry->new(
attempt_code => sub { ... },
retry_if_code => sub { $_[0] =~ /Connection lost/ || $_[1]->{attempt_result} > 20 },
strategy => { Fibonacci => { multiplicator => 2000,
initial_term_index => 3,
max_retries_number => 5,
}
},
on_failure_code => sub { say "Given up retrying" },
);
$action->run();
( run in 1.312 second using v1.01-cache-2.11-cpan-7fcb06a456a )