File Coverage

blib/lib/Resque/Failures.pm
Criterion Covered Total %
statement 9 50 18.0
branch 0 10 0.0
condition 0 21 0.0
subroutine 3 12 25.0
pod 8 8 100.0
total 20 101 19.8


line stmt bran cond sub pod time code
1             package Resque::Failures;
2             # ABSTRACT: Class for managing Resque failures
3             $Resque::Failures::VERSION = '0.41';
4 9     9   89 use Moose;
  9         23  
  9         88  
5             with 'Resque::Encoder';
6 9     9   67516 use Class::Load qw(load_class);
  9         57  
  9         642  
7 9     9   73 use Carp;
  9         21  
  9         8974  
8              
9             has resque => (
10             is => 'ro',
11             required => 1,
12             handles => [qw/ redis key /]
13             );
14              
15             has failure_class => (
16             is => 'rw',
17             lazy => 1,
18             default => sub {
19             load_class('Resque::Failure::Redis');
20             'Resque::Failure::Redis';
21             },
22             trigger => sub {
23             my ( $self, $class ) = @_;
24             load_class($class);
25             }
26             );
27              
28             sub throw {
29 0     0 1   my $self = shift;
30 0           my $e = $self->create(@_);
31 0           $e->save;
32             }
33              
34             sub create {
35 0     0 1   my $self = shift;
36 0           $self->failure_class->new( @_, resque => $self->resque );
37             }
38              
39             sub count {
40 0     0 1   my $self = shift;
41 0           $self->redis->llen($self->key('failed'));
42             }
43              
44             sub all {
45 0     0 1   my ( $self, $start, $count ) = @_;
46 0   0       my $all = $self->resque->list_range(
      0        
47             $self->key('failed'), $start||0, $count||-1
48             );
49 0           $_ = $self->encoder->decode( $_ ) for @$all;
50 0 0         return wantarray ? @$all : $all;
51             }
52              
53             sub clear {
54 0     0 1   my $self = shift;
55 0           $self->redis->del($self->key('failed'));
56             }
57              
58             sub requeue {
59 0     0 1   my ( $self, $index ) = @_;
60 0           my ($item) = $self->all($index, 1);
61 0           $item->{retried_at} = DateTime->now->strftime("%Y/%m/%d %H:%M:%S");
62 0           $self->redis->lset(
63             $self->key('failed'), $index,
64             $self->encoder->encode($item)
65             );
66 0           $self->_requeue($item);
67             }
68              
69             sub _requeue {
70 0     0     my ( $self, $item, $queue ) = @_;
71 0   0       $self->resque->push( $queue || $item->{queue} => $item->{payload} );
72             }
73              
74             sub remove {
75 0     0 1   my ( $self, $index ) = @_;
76 0           my $id = rand(0xffffff);
77 0           my $key = $self->key('failed');
78 0           $self->redis->lset( $key, $index, $id);
79 0           $self->redis->lrem( $key, 1, $id );
80             }
81              
82             sub mass_remove {
83 0     0 1   my ( $self, %opt ) = @_;
84 0   0       $opt{limit} ||= $self->count || return 0;
      0        
85              
86 0 0 0       for (qw/queue error class args/) { $opt{$_} = qr/$opt{$_}/ if $opt{$_} && not ref $opt{$_} }
  0            
87              
88 0           my $key = $self->key('failed');
89 0           my $enc = $self->encoder;
90              
91 0           my ( $count, $rem ) = ( 0, 0 );
92 0           while ( my $encoded_item = $self->redis->lpop($key) ) {
93 0           my $item = $enc->decode($encoded_item);
94              
95             my $match = (!$opt{queue} && !$opt{error} && !$opt{class} && !$opt{args})
96             || (
97             (!$opt{queue} || $item->{queue} =~ $opt{queue})
98             && (!$opt{error} || $item->{error} =~ $opt{error})
99             && (!$opt{class} || $item->{payload}{class} =~ $opt{class})
100             && (!$opt{args} || $enc->encode($item->{payload}{args}) =~ $opt{args})
101 0   0       );
102              
103 0 0 0       if ( $match ) { $rem++; $self->_requeue($item, $opt{requeue_to}) if $opt{requeue} || $opt{requeue_to} }
  0 0          
  0            
104 0           else { $self->redis->rpush( $key => $encoded_item ) }
105              
106 0 0         last if ++$count >= $opt{limit};
107             }
108              
109 0           $rem;
110             }
111              
112             __PACKAGE__->meta->make_immutable();
113              
114             __END__
115              
116             =pod
117              
118             =encoding UTF-8
119              
120             =head1 NAME
121              
122             Resque::Failures - Class for managing Resque failures
123              
124             =head1 VERSION
125              
126             version 0.41
127              
128             =head1 ATTRIBUTES
129              
130             =head2 resque
131              
132             Accessor to the Resque object.
133              
134             =head2 failure_class
135              
136             Name of a class consuming the role 'Resque::Failure'.
137             By default: Resque::Failure::Redis
138              
139             =head1 METHODS
140              
141             =head2 throw
142              
143             create() a failure on the failure_class() and save() it.
144              
145             $failures->throw( %job_description_hash );
146              
147             See L<Resque> code for a usage example.
148              
149             =head2 create
150              
151             Create a new failure on the failure_class() backend.
152              
153             $failures->create( ... );
154              
155             =head2 count
156              
157             How many failures are in the resque system.
158              
159             my $count = $failures->count();
160              
161             =head2 all
162              
163             Return a range of failures (or an arrayref in scalar context)
164             in the same way Resque::peek() does for jobs.
165              
166             my @all = $failures->all; # get all failed jobs
167             my @some = $failures->all(10, 10); # get failure 10 to 20
168              
169             =head2 clear
170              
171             Remove all failures.
172              
173             $failures->clear();
174              
175             =head2 requeue
176              
177             Requeue by index number.
178              
179             Failure will be updated to note retried date.
180              
181             $failures->requeue( $index );
182              
183             =head2 remove
184              
185             Remove failure by index number in failures queue.
186              
187             Please note that, when you remove some index, all
188             sucesive ones will move left, so index will decrese
189             one. If you want to remove several ones start removing
190             from the rightmost one.
191              
192             $failures->remove( $index );
193              
194             =head2 mass_remove
195              
196             Remove and optionally requeue all or matching failed jobs. Errors that happen
197             after this method is fired will remain untouched.
198              
199             Filters, if present, are useful to select failed jobs and should be regexes or
200             strings that will be matched against any of the following failed job field:
201              
202             queue: the queue where job had failed
203             class: the job class
204             error: the error string
205             args: a JSON representation of the job arguments
206              
207             By default, all matching jobs will be deleted but the ones that
208             doesn't match will be placed back at the end of the failed jobs.
209              
210             The behavior can be modified with the following options:
211              
212             requeue: requeue matching jobs after being removed.
213             requeue_to: Requeued jobs will be placed on this queue instead of the original one. This option implies requeue.
214              
215             Example
216              
217             # Remove and requeue all failed jobs from queue 'test_queue' of class My::Job::Class
218             $resque->failures->mass_remove(
219             queue => 'test_queue',
220             class => qr/^My::Job::Class$/,
221             requeue => 1
222             );
223              
224             =head1 AUTHOR
225              
226             Diego Kuperman <diego@freekeylabs.com>
227              
228             =head1 COPYRIGHT AND LICENSE
229              
230             This software is copyright (c) 2021 by Diego Kuperman.
231              
232             This is free software; you can redistribute it and/or modify it under
233             the same terms as the Perl 5 programming language system itself.
234              
235             =cut