File Coverage

blib/lib/Mojo/UserAgent/Role/Retry.pm
Criterion Covered Total %
statement 27 28 96.4
branch 13 14 92.8
condition 4 5 80.0
subroutine 5 5 100.0
pod n/a
total 49 52 94.2


line stmt bran cond sub pod time code
1             package Mojo::UserAgent::Role::Retry 0.003;
2              
3             # ABSTRACT: Retry requests on failure
4              
5 8     8   7877221 use Mojo::Base -role;
  8         8719  
  8         64  
6              
7 8     8   9610 use HTTP::Date qw(str2time);
  8         22180  
  8         913  
8              
9              
10 8   50 8   65 use constant DEBUG => $ENV{MOJO_CLIENT_DEBUG} || 0;
  8         19  
  8         10217  
11              
12             my $_TX_ROLE_RETRY = "Mojo::Transaction::HTTP::Role::Retry";
13              
14              
15             has retries => 5;
16             has retry_wait_min => 1;
17             has retry_wait_max => 20;
18             has retry_policy => sub {
19             return sub {
20             my $tx = shift;
21              
22             my $err = $tx->error;
23             if (!$err) { return 1; }
24              
25             my $code = $err->{code};
26             if (!$code) { return 0; }
27              
28             if ($code == 429 || $code == 503) { return 0; }
29              
30             return 1;
31             };
32             };
33              
34             around build_tx => sub {
35             my ( $orig, $self, @args ) = @_;
36             return $self->$orig(@args)->with_roles($_TX_ROLE_RETRY)->retries(0);
37             };
38              
39             around start => sub {
40             my ( $orig, $self, $tx, $cb ) = @_;
41              
42             if ( !eval { $tx->does($_TX_ROLE_RETRY) } ) {
43             return $self->$orig( $tx, $cb );
44             }
45              
46             if ( $tx->retries > 0 ) {
47             my $remaining = $self->retries - $tx->retries;
48             warn "-- Remaining retries: $remaining" if DEBUG;
49             }
50              
51             if ( !$cb ) {
52             $tx = $self->$orig($tx);
53             if ( $self->retry_policy->($tx) ) { return $tx; }
54             if ( $tx->retries >= $self->retries ) { return $tx; }
55             sleep $self->_retry_wait_time($tx);
56             my $new_tx = Mojo::Transaction::HTTP->with_roles($_TX_ROLE_RETRY)
57             ->new->req( $tx->req->clone )->retries( $tx->retries + 1 );
58             return $self->start( $new_tx, $cb );
59             }
60              
61             return $self->$orig(
62             $tx => sub {
63             my ( $ua, $tx ) = @_;
64             if ( $self->retry_policy->($tx) ) { return $cb->( $ua, $tx ); }
65             if ( $tx->retries >= $self->retries ) { return $cb->( $ua, $tx ); }
66             Mojo::IOLoop->timer(
67             $self->_retry_wait_time($tx) => sub {
68             my $new_tx = Mojo::Transaction::HTTP->with_roles($_TX_ROLE_RETRY)
69             ->new->req( $tx->req->clone )->retries( $tx->retries + 1 );
70             return $self->start( $new_tx, $cb );
71             }
72             );
73             }
74             );
75             };
76              
77             sub _retry_wait_time {
78 17     17   55 my ( $self, $tx ) = @_;
79 17         92 my $wait = $self->retry_wait_min;
80 17 100       112 if ( my $retry_after = $tx->res->headers->header('Retry-After') ) {
81 3         83 $wait = _parse_retry_after($retry_after);
82 3 50       19 if ( $wait == 0 ) { $wait = $self->retry_wait_min; }
  0 100       0  
83 2         15 elsif ( $wait > $self->retry_wait_max ) { $wait = $self->retry_wait_max; }
84             }
85 17         39010248 return $wait;
86             }
87              
88             sub _parse_retry_after {
89 10     10   148912 my $v = shift;
90 10 100       34 if ( !defined $v ) { return 0; }
  1         4  
91 9 100 100     72 if ( $v =~ /^\d+$/ && $v > 0 ) { return $v; }
  4         17  
92 5         17 my $date = str2time($v);
93 5 100       237 if ( !$date ) { return 0; }
  3         12  
94 2 100       8 if ( $date < time ) { return 0; }
  1         4  
95 1         7 return $date - time;
96             }
97              
98             1;
99              
100             __END__