Created
November 1, 2019 21:57
-
-
Save renatocron/2de9cacd817b16e22eb137900b395550 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MojoX::InsistentPromise; | |
use strict; | |
use Carp; | |
use Mojo::IOLoop; | |
use Mojo::Promise; | |
my @retry_timing = (0, 0.5, 1, 3, 7, 13, 21, 34, 55, 60, 120); | |
use Scalar::Util 'weaken'; | |
sub new { | |
my $class = shift; | |
my %opts = @_; | |
croak 'missing option init' unless $opts{init}; | |
croak 'missing option check_sucess' unless $opts{check_sucess}; | |
my $self = bless { | |
init => $opts{init}, | |
check_sucess => $opts{check_sucess}, | |
id => exists $opts{id} ? $opts{id} : undef, | |
retry => exists $opts{retry_timing} ? $opts{retry_timing} : \@retry_timing, | |
should_continue => $opts{should_continue} ? $opts{should_continue} : sub {1}, | |
max_fail => exists $opts{max_fail} ? $opts{max_fail} : 100, | |
fail_count => 0, | |
}; | |
my $ip = Mojo::Promise->new; | |
$self->{promise} = $ip; | |
weaken $self->{promise}; | |
my $inner_p = $self->{init}->($self->{id}); | |
$inner_p->then($self->_success_cb())->catch($self->_fail_cb()); | |
return ($self, $self->{promise}); | |
} | |
sub _exp_retry_fail { | |
my $self = shift; | |
my $value = $self->{retry}->[$self->{fail_count} - 1]; | |
return $value if defined $value; | |
return $self->{retry}[-1] || 15; | |
} | |
sub _success_cb { | |
my ($self) = @_; | |
return sub { | |
my ($response) = @_; | |
if ($self->{check_sucess}->($response, $self->{id})) { | |
$self->{promise}->resolve($response); | |
} | |
else { | |
$self->{fail_count} = $self->{fail_count} + 1; | |
if ($self->{fail_count} < $self->{max_fail}) { | |
my $exp_retry = $self->_exp_retry_fail(); | |
my $inner_p = $self->{init}->($self->{id}); | |
Mojo::IOLoop->timer( | |
$exp_retry => sub { | |
$inner_p->then($self->_success_cb())->catch($self->_fail_cb()); | |
} | |
); | |
} | |
else { | |
$self->{promise}->reject('max_fail reached', $self->{id}, $response); | |
} | |
} | |
return undef; | |
} | |
} | |
sub _fail_cb { | |
my ($self) = @_; | |
return sub { | |
my ($err) = @_; | |
if ( $self->{should_continue}( $err )) { | |
$self->{fail_count} = $self->{fail_count} + 1; | |
if ($self->{fail_count} < $self->{max_fail}) { | |
my $exp_retry = $self->_exp_retry_fail(); | |
my $inner_p = $self->{init}->($self->{id}); | |
Mojo::Promise->all($inner_p); | |
Mojo::IOLoop->timer( | |
$exp_retry => sub { | |
$inner_p->then($self->_success_cb())->catch($self->_fail_cb()); | |
} | |
); | |
}else{ | |
$self->{promise}->reject('toomanyexceptions', $self->{id}, $err); | |
} | |
}else{ | |
$self->{promise}->reject('Aborted due to should_continue=false, id=' . $self->{id}, $err); | |
} | |
return undef; | |
}; | |
} | |
1; |
Author
renatocron
commented
Nov 1, 2019
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment