Action-Retry

 view release on metacpan or  search on metacpan

lib/Action/Retry.pm  view on Meta::CPAN


        if (my $timestamp = $self->_needs_sleeping_until) {
            # we can't retry until we have waited enough time 
            my ($seconds, $microseconds) = gettimeofday;
            $seconds * 1000 + int($microseconds / 1000) >= $timestamp
              or return;
            $self->_needs_sleeping_until(0);
            $self->strategy->next_step;
        }

        my $error;
        my @attempt_result;
        my $attempt_result;
        my $wantarray;
          
        if (wantarray) {
            $wantarray = 1;
            @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;
        }

lib/Action/Retry.pm  view on Meta::CPAN

C<retry_if_code> return value will be interpreted as a boolean : true return
value means the execution of C<attempt_code> was a failure and it needs to be
retried. False means it went well.

Here is an example of code that gets the arguments properly:

  my $action = Action::Retry->new(
    attempt_code => sub { do_stuff; } )->run();
    attempt_code => sub { map { $_ * 2 } @_ }
    retry_if_code => sub {
      my ($error, $h) = @_;

      my $attempt_code_result = $h->{attempt_result};
      my $attempt_code_params = $h->{attempt_parameters};

      my @results = @$attempt_code_result;
      # will contains (2, 4);

      my @original_parameters = @$attempt_code_params;
      # will contains (1, 2);

lib/Action/Retry.pm  view on Meta::CPAN


=head2 run

Does the following:

=over

=item step 1

Runs the C<attempt_code> CodeRef in the proper context in an eval {} block,
saving C<$@> in C<$error>.

=item step 2

Runs the C<retry_if_code> CodeRef in scalar context, giving it as arguments
C<$error>, and the return values of C<attempt_code>. If it returns true, we
consider that it was a failure, and move to step 3. Otherwise, we consider it
means success, and return the return values of C<attempt_code>.

=item step 3

Ask the C<strategy> if it's still useful to retry. If yes, sleep accordingly,
and go back to step 2. If not, go to step 4.

=item step 4

Runs the C<on_failure_code> CodeRef in the proper context, giving it as
arguments C<$error>, and the return values of C<attempt_code>, and returns the
results back to the caller.

=back

Arguments passed to C<run()> will be passed to C<attempt_code>. They will also
passed to C<on_failure_code> as well if the case arises.

=head2 retry

  retry { ..code.. } some => 'arguments';

t/check_params.t  view on Meta::CPAN


use strict;
use warnings;

use Test::More;

{
    my $var = 0;
    my $action = Action::Retry->new(
        attempt_code => sub { my ($val) = @_; $var++; die "plop\n" if $var < 5; return $var + $val; },
        retry_if_code => sub { my ($error, $h) = @_;
                               chomp $error;
                               if ($var < 5) {
                                   is $error, "plop";
                                   return 1;
                               } else {
                                   ok ! $error;
                                   is $h->{attempt_result}, $var + $h->{attempt_parameters}[0];
                                   return 0;
                               }
                           },
        strategy => { Fibonacci => { initial_term_index => 0, multiplicator => 10 } },
    );
    my $result = $action->run(2);
    is($result, 7);
}

t/fibonacci.t  view on Meta::CPAN

}

{
    my @expected = (5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610);
    my @got;

    my $var = 0;
    my $acc = 0;
    my $action = Action::Retry->new(
        attempt_code => sub { my ($val) = @_; $acc+=$val; $var++; die "plop" },
        retry_if_code => sub { my ($error, $h) = @_; push @got, $h->{action_retry}->strategy->compute_sleep_time; $error; },
        strategy => { Fibonacci => { initial_term_index => 5, multiplicator => 1 } },
    );
    $action->run(2);
    is($var, 11);
    is($acc, 22);
    is_deeply(\@got, \@expected, 'starting with an initial_term_index works');
}
done_testing;



( run in 0.250 second using v1.01-cache-2.11-cpan-65fba6d93b7 )