Skip to content

Instantly share code, notes, and snippets.

@renatocron
Created October 30, 2019 12:30
Show Gist options
  • Save renatocron/4ca419f1dbb6b3117060f9a9cae6e403 to your computer and use it in GitHub Desktop.
Save renatocron/4ca419f1dbb6b3117060f9a9cae6e403 to your computer and use it in GitHub Desktop.
package MojoX::InsistentPromise;
use strict;
use Carp;
my @retry_pos = (0, 0.5, 1, 3, 7, 13, 21, 34, 55, 60, 120);
$_ = $_ / 10000 for @retry_pos; # Test only!
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_pos} ? $opts{retry_pos} : \@retry_pos,
max_fail_num => exists $opts{max_fail} ? $opts{max_fail} : 100,
};
my $insistent_promises = Mojo::Promise->new;
$self->{promise} = $insistent_promises;
weaken $self->{promise};
my $inner_p = $self->{init}->($self->{id});
#weaken $inner_p;
$inner_p->then($self->_success_cb(0))->catch($self->_fail_cb(0));
return ($self, $insistent_promises);
}
sub promise {
return shift->{promise};
}
sub _exp_retry_fail {
my $self = shift;
my $fail_num = shift;
return $self->{retry}->[$fail_num] || $self->{retry}[-1];
}
sub _success_cb {
my ($self, $fail_count) = @_;
$fail_count ||= 0;
#use DDP; p ['_success_cb', $self];
return sub {
my ($response) = @_;
if ($self->{check_sucess}->($response)) {
$self->promise->resolve($response);
}
else {
$fail_count++;
if ($fail_count < $self->{max_fail_num}) {
my $exp_retry = $self->_exp_retry_fail($fail_count - 1);
my $inner_p = $self->{init}->($self->{id});
#weaken $inner_p;
#Mojo::IOLoop->timer(
# $exp_retry => sub {
$inner_p->then($self->_success_cb($fail_count))
->catch($self->_fail_cb($fail_count));
# }
#);
}
else {
$self->promise->reject($self->{id});
}
}
return undef;
}
}
sub _fail_cb {
my ($self, $fail_count) = @_;
$fail_count ||= 0;
#use DDP; p ['_fail_cb', $self];
return sub {
my ($err) = @_;
$fail_count++;
if ($fail_count < $self->{max_fail_num}) {
my $exp_retry = &_exp_retry_fail($fail_count - 1);
my $inner_p = $self->{init}->($self->{id});
#weaken $inner_p;
#Mojo::IOLoop->timer(
# $exp_retry => sub {
$inner_p->then($self->_success_cb($fail_count))
->catch($self->_fail_cb($fail_count));
# }
#);
}
else {
$self->promise->reject($self->{id});
}
return undef;
};
}
package main;
use strict;
use Mojo::Promise;
use Mojo::UserAgent;
use DDP;
use Memory::Usage;
my $mu = Memory::Usage->new();
my $ua = Mojo::UserAgent->new->inactivity_timeout(1);
my $max_fail_num = 100;
my $total_success = 0;
my $total_err = 0;
my %current_p;
my $errored;
my $pid = 0;
$mu->record('starting work');
for my $num (1 .. 20) {
my $url = 'http://localhost:3000/maybe_fail?num=' . $num;
my ($ipo, $ip) = MojoX::InsistentPromise->new(
check_sucess => sub {
my $tx = shift;
return $tx->res->code == 200;
},
init => sub {
return $ua->get_p($url);
},
);
my $mine_pid = $pid++;
$current_p{$mine_pid} = $ip;
#$ua->get_p($url)->then(&_success_cb($insistent_promises, $url, 0))
# ->catch(_fail_cb($insistent_promises, $url, 0));
$ipo->promise->then(
sub {
my ($res) = @_;
$total_success++;
}
)->catch(
sub {
print STDERR "cancel everythiiiiiiiiiiing!!!\n\n\n";
$errored++;
#Mojo::Promise->reset;
}
)->finally(
sub {
delete $current_p{$mine_pid};
}
);
#Mojo::Promise->all($ipo->promise);
$mu->record('Iteration ' . $num) if $num % 1000 == 0;
#if (scalar keys %current_p > 5) {
# Mojo::Promise->race(values %current_p)->wait;
#}
}
my @values = values %current_p;
use DDP;
p \@values;
Mojo::Promise->all(@values)->wait if @values;
$mu->record('Last Iteration');
$mu->dump();
if ($errored) {
die "Please do not commit!!!\n";
}
p [$total_success, $total_err];
exit;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment