File Coverage

blib/lib/Minion.pm
Criterion Covered Total %
statement 39 129 30.2
branch 0 42 0.0
condition 0 12 0.0
subroutine 13 45 28.8
pod 21 21 100.0
total 73 249 29.3


line stmt bran cond sub pod time code
1             package Minion;
2 2     2   538272 use Mojo::Base 'Mojo::EventEmitter';
  2         4  
  2         17  
3              
4 2     2   4855 use Carp qw(croak);
  2         5  
  2         127  
5 2     2   47 use Config;
  2         14  
  2         90  
6 2     2   1006 use Minion::Iterator;
  2         6  
  2         13  
7 2     2   1196 use Minion::Job;
  2         8  
  2         18  
8 2     2   1631 use Minion::Worker;
  2         8  
  2         21  
9 2     2   1375 use Mojo::Date;
  2         9123  
  2         19  
10 2     2   90 use Mojo::IOLoop;
  2         2  
  2         27  
11 2     2   58 use Mojo::Loader qw(load_class);
  2         3  
  2         89  
12 2     2   10 use Mojo::Promise;
  2         3  
  2         14  
13 2     2   1015 use Mojo::Server;
  2         4096  
  2         15  
14 2     2   93 use Mojo::Util qw(scope_guard steady_time);
  2         6  
  2         150  
15 2     2   1276 use YAML::XS qw(Dump);
  2         7631  
  2         6282  
16              
17             has app => sub { $_[0]{app_ref} = Mojo::Server->new->build_app('Mojo::HelloWorld') }, weak => 1;
18             has 'backend';
19             has backoff => sub { \&_backoff };
20             has missing_after => 1800;
21             has [qw(remove_after stuck_after)] => 172800;
22             has tasks => sub { {} };
23              
24             our $VERSION = '11.0';
25              
26             sub add_task {
27 0     0 1   my ($self, $name, $task) = @_;
28              
29 0 0         unless (ref $task) {
30 0           my $e = load_class $task;
31 0 0         croak ref $e ? $e : qq{Task "$task" missing} if $e;
    0          
32 0 0         croak qq{Task "$task" is not a Minion::Job subclass} unless $task->isa('Minion::Job');
33             }
34 0           $self->tasks->{$name} = $task;
35              
36 0           return $self;
37             }
38              
39 0     0 1   sub broadcast { shift->backend->broadcast(@_) }
40              
41             sub class_for_task {
42 0     0 1   my ($self, $task) = @_;
43 0           my $class = $self->tasks->{$task};
44 0 0 0       return !$class || ref $class ? 'Minion::Job' : $class;
45             }
46              
47             sub enqueue {
48 0     0 1   my $self = shift;
49 0           my $id = $self->backend->enqueue(@_);
50 0           $self->emit(enqueue => $id);
51 0           return $id;
52             }
53              
54             sub foreground {
55 0     0 1   my ($self, $id) = @_;
56              
57 0 0         return undef unless my $job = $self->job($id);
58 0 0         return undef unless $job->retry({attempts => 1, queue => 'minion_foreground'});
59              
60             # Reset event loop
61 0           Mojo::IOLoop->reset;
62 0           local $SIG{CHLD} = local $SIG{INT} = local $SIG{TERM} = local $SIG{QUIT} = 'DEFAULT';
63              
64 0           my $worker = $self->worker->register;
65 0           $job = $worker->dequeue(0 => {id => $id, queues => ['minion_foreground']});
66 0           my $err;
67 0 0         if ($job) { defined($err = $job->execute) ? $job->fail($err) : $job->finish }
  0 0          
68 0           $worker->unregister;
69              
70 0 0         return defined $err ? die $err : !!$job;
71             }
72              
73             sub guard {
74 0     0 1   my ($self, $name, $duration, $options) = @_;
75 0           my $time = steady_time + $duration;
76 0 0         return undef unless $self->lock($name, $duration, $options);
77 0 0   0     return scope_guard sub { $self->unlock($name) if steady_time < $time };
  0            
78             }
79              
80 0     0 1   sub history { shift->backend->history }
81              
82 0     0 1   sub is_locked { !shift->lock(shift, 0) }
83              
84             sub job {
85 0     0 1   my ($self, $id) = @_;
86              
87 0 0         return undef unless my $job = $self->_info($id);
88             return $self->class_for_task($job->{task})
89 0           ->new(args => $job->{args}, id => $job->{id}, minion => $self, retries => $job->{retries}, task => $job->{task});
90             }
91              
92 0     0 1   sub jobs { shift->_iterator(1, @_) }
93              
94 0     0 1   sub lock { shift->backend->lock(@_) }
95              
96             sub new {
97 0     0 1   my $self = shift->SUPER::new;
98              
99 0           my $class = 'Minion::Backend::' . shift;
100 0           my $e = load_class $class;
101 0 0         croak ref $e ? $e : qq{Backend "$class" missing} if $e;
    0          
102              
103 0           return $self->backend($class->new(@_)->minion($self));
104             }
105              
106 0     0 1   sub perform_jobs { _perform_jobs(0, @_) }
107 0     0 1   sub perform_jobs_in_foreground { _perform_jobs(1, @_) }
108              
109 0     0 1   sub repair { shift->_delegate('repair') }
110              
111 0     0 1   sub reset { shift->_delegate('reset', @_) }
112              
113             sub result_p {
114 0   0 0 1   my ($self, $id, $options) = (shift, shift, shift // {});
115              
116 0           my $promise = Mojo::Promise->new;
117 0     0     my $cb = sub { $self->_result($promise, $id) };
  0            
118 0   0       my $timer = Mojo::IOLoop->recurring($options->{interval} // 3 => $cb);
119 0     0     $promise->finally(sub { Mojo::IOLoop->remove($timer) })->catch(sub { });
  0            
120 0           $cb->();
121              
122 0           return $promise;
123             }
124              
125 0     0 1   sub stats { shift->backend->stats }
126 0     0 1   sub unlock { shift->backend->unlock(@_) }
127              
128             sub worker {
129 0     0 1   my $self = shift;
130              
131             # No fork emulation support
132 0 0         croak 'Minion workers do not support fork emulation' if $Config{d_pseudofork};
133              
134 0           my $worker = Minion::Worker->new(minion => $self);
135 0           $self->emit(worker => $worker);
136 0           return $worker;
137             }
138              
139 0     0 1   sub workers { shift->_iterator(0, @_) }
140              
141 0     0     sub _backoff { (shift()**4) + 15 }
142              
143             # Used by the job command and admin plugin
144             sub _datetime {
145 0     0     my $hash = shift;
146             $hash->{$_} and $hash->{$_} = Mojo::Date->new($hash->{$_})->to_datetime
147 0   0       for qw(created delayed expires finished notified retried started time);
148 0           return $hash;
149             }
150              
151             sub _delegate {
152 0     0     my ($self, $method) = (shift, shift);
153 0           $self->backend->$method(@_);
154 0           return $self;
155             }
156              
157 0     0     sub _dump { local $YAML::XS::Boolean = 'JSON::PP'; Dump(@_) }
  0            
158              
159             sub _iterator {
160 0   0 0     my ($self, $jobs, $options) = (shift, shift, shift // {});
161 0           return Minion::Iterator->new(minion => $self, options => $options, jobs => $jobs);
162             }
163              
164 0     0     sub _info { shift->backend->list_jobs(0, 1, {ids => [shift]})->{jobs}[0] }
165              
166             sub _perform_jobs {
167 0     0     my ($foreground, $minion, $options) = @_;
168              
169 0           my $worker = $minion->worker;
170 0           while (my $job = $worker->register->dequeue(0, $options)) {
171 0 0         if (!$foreground) { $job->perform }
  0 0          
172 0           elsif (defined(my $err = $job->execute)) { $job->fail($err) }
173 0           else { $job->finish }
174             }
175 0           $worker->unregister;
176             }
177              
178             sub _result {
179 0     0     my ($self, $promise, $id) = @_;
180 0 0         return $promise->resolve unless my $job = $self->_info($id);
181 0 0         if ($job->{state} eq 'finished') { $promise->resolve($job) }
  0 0          
182 0           elsif ($job->{state} eq 'failed') { $promise->reject($job) }
183             }
184              
185             1;
186              
187             =encoding utf8
188              
189             =head1 NAME
190              
191             Minion - Job queue
192              
193             =head1 SYNOPSIS
194              
195             use Minion;
196              
197             # Connect to backend
198             my $minion = Minion->new(Pg => 'postgresql://postgres@/test');
199              
200             # Add tasks
201             $minion->add_task(something_slow => sub ($job, @args) {
202             sleep 5;
203             say 'This is a background worker process.';
204             });
205              
206             # Enqueue jobs
207             $minion->enqueue(something_slow => ['foo', 'bar']);
208             $minion->enqueue(something_slow => [1, 2, 3] => {priority => 5});
209              
210             # Perform jobs for testing
211             $minion->enqueue(something_slow => ['foo', 'bar']);
212             $minion->perform_jobs;
213              
214             # Start a worker to perform up to 12 jobs concurrently
215             my $worker = $minion->worker;
216             $worker->status->{jobs} = 12;
217             $worker->run;
218              
219             =head1 DESCRIPTION
220              
221             =begin html
222              
223            

224             Screenshot
225            

226              
227             =end html
228              
229             L is a high performance job queue for the Perl programming language, with support for multiple named queues,
230             priorities, high priority fast lane, delayed jobs, job dependencies, job progress, job results, retries with backoff,
231             rate limiting, unique jobs, expiring jobs, statistics, distributed workers, parallel processing, autoscaling, remote
232             control, L admin ui, resource leak protection and multiple backends (such as
233             L).
234              
235             Job queues allow you to process time and/or computationally intensive tasks in background processes, outside of the
236             request/response lifecycle of web applications. Among those tasks you'll commonly find image resizing, spam filtering,
237             HTTP downloads, building tarballs, warming caches and basically everything else you can imagine that's not super fast.
238              
239             Take a look at our excellent documentation in L!
240              
241             =head1 EXAMPLES
242              
243             This distribution also contains a great example application you can use for inspiration. The L
244             checker|https://github.com/mojolicious/minion/tree/main/examples/linkcheck> will show you how to integrate background
245             jobs into well-structured L applications.
246              
247             =head1 EVENTS
248              
249             L inherits all events from L and can emit the following new ones.
250              
251             =head2 enqueue
252              
253             $minion->on(enqueue => sub ($minion, $id) {
254             ...
255             });
256              
257             Emitted after a job has been enqueued, in the process that enqueued it.
258              
259             $minion->on(enqueue => sub ($minion, $id) {
260             say "Job $id has been enqueued.";
261             });
262              
263             =head2 worker
264              
265             $minion->on(worker => sub ($minion, $worker) {
266             ...
267             });
268              
269             Emitted in the worker process after it has been created.
270              
271             $minion->on(worker => sub ($minion, $worker) {
272             say "Worker $$ started.";
273             });
274              
275             =head1 ATTRIBUTES
276              
277             L implements the following attributes.
278              
279             =head2 app
280              
281             my $app = $minion->app;
282             $minion = $minion->app(MyApp->new);
283              
284             Application for job queue, defaults to a L object. Note that this attribute is weakened.
285              
286             =head2 backend
287              
288             my $backend = $minion->backend;
289             $minion = $minion->backend(Minion::Backend::Pg->new);
290              
291             Backend, usually a L object.
292              
293             =head2 backoff
294              
295             my $cb = $minion->backoff;
296             $minion = $minion->backoff(sub {...});
297              
298             A callback used to calculate the delay for automatically retried jobs, defaults to C<(retries ** 4) + 15> (15, 16, 31,
299             96, 271, 640...), which means that roughly C<25> attempts can be made in C<21> days.
300              
301             $minion->backoff(sub ($retries) {
302             return ($retries ** 4) + 15 + int(rand 30);
303             });
304              
305             =head2 missing_after
306              
307             my $after = $minion->missing_after;
308             $minion = $minion->missing_after(172800);
309              
310             Amount of time in seconds after which workers without a heartbeat will be considered missing and removed from the
311             registry by L, defaults to C<1800> (30 minutes).
312              
313             =head2 remove_after
314              
315             my $after = $minion->remove_after;
316             $minion = $minion->remove_after(86400);
317              
318             Amount of time in seconds after which jobs that have reached the state C and have no unresolved dependencies
319             will be removed automatically by L, defaults to C<172800> (2 days). It is not recommended to set this value
320             below 2 days.
321              
322             =head2 stuck_after
323              
324             my $after = $minion->stuck_after;
325             $minion = $minion->stuck_after(86400);
326              
327             Amount of time in seconds after which jobs that have not been processed will be considered stuck by L and
328             transition to the C state, defaults to C<172800> (2 days).
329              
330             =head2 tasks
331              
332             my $tasks = $minion->tasks;
333             $minion = $minion->tasks({foo => sub {...}});
334              
335             Registered tasks.
336              
337             =head1 METHODS
338              
339             L inherits all methods from L and implements the following new ones.
340              
341             =head2 add_task
342              
343             $minion = $minion->add_task(foo => sub {...});
344             $minion = $minion->add_task(foo => 'MyApp::Task::Foo');
345              
346             Register a task, which can be a closure or a custom L subclass. Note that support for custom task classes
347             is B and might change without warning!
348              
349             # Job with result
350             $minion->add_task(add => sub ($job, $first, $second) {
351             $job->finish($first + $second);
352             });
353             my $id = $minion->enqueue(add => [1, 1]);
354             my $result = $minion->job($id)->info->{result};
355              
356             =head2 broadcast
357              
358             my $bool = $minion->broadcast('some_command');
359             my $bool = $minion->broadcast('some_command', [@args]);
360             my $bool = $minion->broadcast('some_command', [@args], [$id1, $id2, $id3]);
361              
362             Broadcast remote control command to one or more workers.
363              
364             # Broadcast "stop" command to all workers to kill job 10025
365             $minion->broadcast('stop', [10025]);
366              
367             # Broadcast "kill" command to all workers to interrupt job 10026
368             $minion->broadcast('kill', ['INT', 10026]);
369              
370             # Broadcast "jobs" command to pause worker 23
371             $minion->broadcast('jobs', [0], [23]);
372              
373             # Broadcast "spare" command to disable the feature on all workers
374             $minion->broadcast('spare', [0]);
375              
376             =head2 class_for_task
377              
378             my $class = $minion->class_for_task('foo');
379              
380             Return job class for task. Note that this method is B and might change without warning!
381              
382             =head2 enqueue
383              
384             my $id = $minion->enqueue('foo');
385             my $id = $minion->enqueue(foo => [@args]);
386             my $id = $minion->enqueue(foo => [@args] => {priority => 1});
387              
388             Enqueue a new job with C state. Arguments get serialized by the L (often with L), so
389             you shouldn't send objects and be careful with binary data, nested data structures with hash and array references are
390             fine though.
391              
392             These options are currently available:
393              
394             =over 2
395              
396             =item attempts
397              
398             attempts => 25
399              
400             Number of times performing this job will be attempted, with a delay based on L after the first attempt,
401             defaults to C<1>.
402              
403             =item delay
404              
405             delay => 10
406              
407             Delay job for this many seconds (from now), defaults to C<0>.
408              
409             =item expire
410              
411             expire => 300
412              
413             Job is valid for this many seconds (from now) before it expires.
414              
415             =item lax
416              
417             lax => 1
418              
419             Existing jobs this job depends on may also have transitioned to the C state to allow for it to be processed,
420             defaults to C.
421              
422             =item notes
423              
424             notes => {foo => 'bar', baz => [1, 2, 3]}
425              
426             Hash reference with arbitrary metadata for this job that gets serialized by the L (often with
427             L), so you shouldn't send objects and be careful with binary data, nested data structures with hash and
428             array references are fine though.
429              
430             =item parents
431              
432             parents => [$id1, $id2, $id3]
433              
434             One or more existing jobs this job depends on, and that need to have transitioned to the state C before it
435             can be processed.
436              
437             =item priority
438              
439             priority => 5
440              
441             Job priority, defaults to C<0>. Jobs with a higher priority get performed first. Priorities can be positive or negative,
442             but should be in the range between C<100> and C<-100>.
443              
444             =item queue
445              
446             queue => 'important'
447              
448             Queue to put job in, defaults to C.
449              
450             =back
451              
452             =head2 foreground
453              
454             my $bool = $minion->foreground($id);
455              
456             Retry job in C queue, then perform it right away with a temporary worker in this process, very
457             useful for debugging.
458              
459             =head2 guard
460              
461             my $guard = $minion->guard('foo', 3600);
462             my $guard = $minion->guard('foo', 3600, {limit => 20});
463              
464             Same as L, but returns a scope guard object that automatically releases the lock as soon as the object is
465             destroyed, or C if aquiring the lock failed.
466              
467             # Only one job should run at a time (unique job)
468             $minion->add_task(do_unique_stuff => sub ($job, @args) {
469             return $job->finish('Previous job is still active')
470             unless my $guard = $minion->guard('fragile_backend_service', 7200);
471             ...
472             });
473              
474             # Only five jobs should run at a time and we try again later if necessary
475             $minion->add_task(do_concurrent_stuff => sub ($job, @args) {
476             return $job->retry({delay => 30})
477             unless my $guard = $minion->guard('some_web_service', 60, {limit => 5});
478             ...
479             });
480              
481             =head2 history
482              
483             my $history = $minion->history;
484              
485             Get history information for job queue.
486              
487             These fields are currently available:
488              
489             =over 2
490              
491             =item daily
492              
493             daily => [{epoch => 12345, finished_jobs => 95, failed_jobs => 2}, ...]
494              
495             Hourly counts for processed jobs from the past day.
496              
497             =back
498              
499             =head2 is_locked
500              
501             my $bool = $minion->is_locked('foo');
502              
503             Check if a lock with that name is currently active.
504              
505             =head2 job
506              
507             my $job = $minion->job($id);
508              
509             Get L object without making any changes to the actual job or return C if job does not exist.
510              
511             # Check job state
512             my $state = $minion->job($id)->info->{state};
513              
514             # Get job metadata
515             my $progress = $minion->job($id)->info->{notes}{progress};
516              
517             # Get job result
518             my $result = $minion->job($id)->info->{result};
519              
520             =head2 jobs
521              
522             my $jobs = $minion->jobs;
523             my $jobs = $minion->jobs({states => ['inactive']});
524              
525             Return L object to safely iterate through job information.
526              
527             # Iterate through jobs for two tasks
528             my $jobs = $minion->jobs({tasks => ['foo', 'bar']});
529             while (my $info = $jobs->next) {
530             say "$info->{id}: $info->{state}";
531             }
532              
533             # Remove all failed jobs from a named queue
534             my $jobs = $minion->jobs({states => ['failed'], queues => ['unimportant']});
535             while (my $info = $jobs->next) {
536             $minion->job($info->{id})->remove;
537             }
538              
539             # Count failed jobs for a task
540             say $minion->jobs({states => ['failed'], tasks => ['foo']})->total;
541              
542             These options are currently available:
543              
544             =over 2
545              
546             =item ids
547              
548             ids => ['23', '24']
549              
550             List only jobs with these ids.
551              
552             =item notes
553              
554             notes => ['foo', 'bar']
555              
556             List only jobs with one of these notes.
557              
558             =item queues
559              
560             queues => ['important', 'unimportant']
561              
562             List only jobs in these queues.
563              
564             =item states
565              
566             states => ['inactive', 'active']
567              
568             List only jobs in these states.
569              
570             =item tasks
571              
572             tasks => ['foo', 'bar']
573              
574             List only jobs for these tasks.
575              
576             =back
577              
578             These fields are currently available:
579              
580             =over 2
581              
582             =item args
583              
584             args => ['foo', 'bar']
585              
586             Job arguments.
587              
588             =item attempts
589              
590             attempts => 25
591              
592             Number of times performing this job will be attempted.
593              
594             =item children
595              
596             children => ['10026', '10027', '10028']
597              
598             Jobs depending on this job.
599              
600             =item created
601              
602             created => 784111777
603              
604             Epoch time job was created.
605              
606             =item delayed
607              
608             delayed => 784111777
609              
610             Epoch time job was delayed to.
611              
612             =item expires
613              
614             expires => 784111777
615              
616             Epoch time job is valid until before it expires.
617              
618             =item finished
619              
620             finished => 784111777
621              
622             Epoch time job was finished.
623              
624             =item id
625              
626             id => 10025
627              
628             Job id.
629              
630             =item lax
631              
632             lax => 0
633              
634             Existing jobs this job depends on may also have failed to allow for it to be processed.
635              
636             =item notes
637              
638             notes => {foo => 'bar', baz => [1, 2, 3]}
639              
640             Hash reference with arbitrary metadata for this job.
641              
642             =item parents
643              
644             parents => ['10023', '10024', '10025']
645              
646             Jobs this job depends on.
647              
648             =item priority
649              
650             priority => 3
651              
652             Job priority.
653              
654             =item queue
655              
656             queue => 'important'
657              
658             Queue name.
659              
660             =item result
661              
662             result => 'All went well!'
663              
664             Job result.
665              
666             =item retried
667              
668             retried => 784111777
669              
670             Epoch time job has been retried.
671              
672             =item retries
673              
674             retries => 3
675              
676             Number of times job has been retried.
677              
678             =item started
679              
680             started => 784111777
681              
682             Epoch time job was started.
683              
684             =item state
685              
686             state => 'inactive'
687              
688             Current job state, usually C, C, C or C.
689              
690             =item task
691              
692             task => 'foo'
693              
694             Task name.
695              
696             =item time
697              
698             time => 78411177
699              
700             Server time.
701              
702             =item worker
703              
704             worker => '154'
705              
706             Id of worker that is processing the job.
707              
708             =back
709              
710             =head2 lock
711              
712             my $bool = $minion->lock('foo', 3600);
713             my $bool = $minion->lock('foo', 3600, {limit => 20});
714              
715             Try to acquire a named lock that will expire automatically after the given amount of time in seconds. You can release
716             the lock manually with L to limit concurrency, or let it expire for rate limiting. For convenience you can
717             also use L to release the lock automatically, even if the job failed.
718              
719             # Only one job should run at a time (unique job)
720             $minion->add_task(do_unique_stuff => sub ($job, @args) {
721             return $job->finish('Previous job is still active')
722             unless $minion->lock('fragile_backend_service', 7200);
723             ...
724             $minion->unlock('fragile_backend_service');
725             });
726              
727             # Only five jobs should run at a time and we wait for our turn
728             $minion->add_task(do_concurrent_stuff => sub ($job, @args) {
729             sleep 1 until $minion->lock('some_web_service', 60, {limit => 5});
730             ...
731             $minion->unlock('some_web_service');
732             });
733              
734             # Only a hundred jobs should run per hour and we try again later if necessary
735             $minion->add_task(do_rate_limited_stuff => sub ($job, @args) {
736             return $job->retry({delay => 3600})
737             unless $minion->lock('another_web_service', 3600, {limit => 100});
738             ...
739             });
740              
741             An expiration time of C<0> can be used to check if a named lock could have been acquired without creating one.
742              
743             # Check if the lock "foo" could have been acquired
744             say 'Lock could have been acquired' unless $minion->lock('foo', 0);
745              
746             Or to simply check if a named lock already exists you can also use L.
747              
748             These options are currently available:
749              
750             =over 2
751              
752             =item limit
753              
754             limit => 20
755              
756             Number of shared locks with the same name that can be active at the same time, defaults to C<1>.
757              
758             =back
759              
760             =head2 new
761              
762             my $minion = Minion->new(Pg => 'postgresql://postgres@/test');
763             my $minion = Minion->new(Pg => Mojo::Pg->new);
764              
765             Construct a new L object.
766              
767             =head2 perform_jobs
768              
769             $minion->perform_jobs;
770             $minion->perform_jobs({queues => ['important']});
771              
772             Perform all jobs with a temporary worker, very useful for testing.
773              
774             # Longer version
775             my $worker = $minion->worker;
776             while (my $job = $worker->register->dequeue(0)) { $job->perform }
777             $worker->unregister;
778              
779             These options are currently available:
780              
781             =over 2
782              
783             =item id
784              
785             id => '10023'
786              
787             Dequeue a specific job.
788              
789             =item min_priority
790              
791             min_priority => 3
792              
793             Do not dequeue jobs with a lower priority.
794              
795             =item queues
796              
797             queues => ['important']
798              
799             One or more queues to dequeue jobs from, defaults to C.
800              
801             =back
802              
803             =head2 perform_jobs_in_foreground
804              
805             $minion->perform_jobs_in_foreground;
806             $minion->perform_jobs_in_foreground({queues => ['important']});
807              
808             Same as L, but all jobs are performed in the current process, without spawning new processes.
809              
810             =head2 repair
811              
812             $minion = $minion->repair;
813              
814             Repair worker registry and job queue if necessary.
815              
816             =head2 reset
817              
818             $minion = $minion->reset({all => 1});
819              
820             Reset job queue.
821              
822             These options are currently available:
823              
824             =over 2
825              
826             =item all
827              
828             all => 1
829              
830             Reset everything.
831              
832             =item locks
833              
834             locks => 1
835              
836             Reset only locks.
837              
838             =back
839              
840             =head2 result_p
841              
842             my $promise = $minion->result_p($id);
843             my $promise = $minion->result_p($id, {interval => 5});
844              
845             Return a L object for the result of a job. The state C will result in the promise being
846             C, and the state C in the promise being C. This operation can be cancelled by resolving
847             the promise manually at any time.
848              
849             # Enqueue job and receive the result at some point in the future
850             my $id = $minion->enqueue('foo');
851             $minion->result_p($id)->then(sub ($info) {
852             my $result = ref $info ? $info->{result} : 'Job already removed';
853             say "Finished: $result";
854             })->catch(sub ($info) {
855             say "Failed: $info->{result}";
856             })->wait;
857              
858             These options are currently available:
859              
860             =over 2
861              
862             =item interval
863              
864             interval => 5
865              
866             Polling interval in seconds for checking if the state of the job has changed, defaults to C<3>.
867              
868             =back
869              
870             =head2 stats
871              
872             my $stats = $minion->stats;
873              
874             Get statistics for the job queue.
875              
876             # Check idle workers
877             my $idle = $minion->stats->{inactive_workers};
878              
879             These fields are currently available:
880              
881             =over 2
882              
883             =item active_jobs
884              
885             active_jobs => 100
886              
887             Number of jobs in C state.
888              
889             =item active_locks
890              
891             active_locks => 100
892              
893             Number of active named locks.
894              
895             =item active_workers
896              
897             active_workers => 100
898              
899             Number of workers that are currently processing a job.
900              
901             =item delayed_jobs
902              
903             delayed_jobs => 100
904              
905             Number of jobs in C state that are scheduled to run at specific time in the future or have unresolved
906             dependencies.
907              
908             =item enqueued_jobs
909              
910             enqueued_jobs => 100000
911              
912             Rough estimate of how many jobs have ever been enqueued.
913              
914             =item failed_jobs
915              
916             failed_jobs => 100
917              
918             Number of jobs in C state.
919              
920             =item finished_jobs
921              
922             finished_jobs => 100
923              
924             Number of jobs in C state.
925              
926             =item inactive_jobs
927              
928             inactive_jobs => 100
929              
930             Number of jobs in C state.
931              
932             =item inactive_workers
933              
934             inactive_workers => 100
935              
936             Number of workers that are currently not processing a job.
937              
938             =item uptime
939              
940             uptime => 1000
941              
942             Uptime in seconds.
943              
944             =item workers
945              
946             workers => 200;
947              
948             Number of registered workers.
949              
950             =back
951              
952             =head2 unlock
953              
954             my $bool = $minion->unlock('foo');
955              
956             Release a named lock that has been previously acquired with L.
957              
958             =head2 worker
959              
960             my $worker = $minion->worker;
961              
962             Build L object. Note that this method should only be used to implement custom workers.
963              
964             # Use the standard worker with all its features
965             my $worker = $minion->worker;
966             $worker->status->{jobs} = 12;
967             $worker->status->{queues} = ['important'];
968             $worker->run;
969              
970             # Perform one job manually in a separate process
971             my $worker = $minion->repair->worker->register;
972             my $job = $worker->dequeue(5);
973             $job->perform;
974             $worker->unregister;
975              
976             # Perform one job manually in this process
977             my $worker = $minion->repair->worker->register;
978             my $job = $worker->dequeue(5);
979             if (my $err = $job->execute) { $job->fail($err) }
980             else { $job->finish }
981             $worker->unregister;
982              
983             # Build a custom worker performing multiple jobs at the same time
984             my %jobs;
985             my $worker = $minion->repair->worker->register;
986             do {
987             for my $id (keys %jobs) {
988             delete $jobs{$id} if $jobs{$id}->is_finished;
989             }
990             if (keys %jobs >= 4) { sleep 5 }
991             else {
992             my $job = $worker->dequeue(5);
993             $jobs{$job->id} = $job->start if $job;
994             }
995             } while keys %jobs;
996             $worker->unregister;
997              
998             =head2 workers
999              
1000             my $workers = $minion->workers;
1001             my $workers = $minion->workers({ids => [2, 3]});
1002              
1003             Return L object to safely iterate through worker information.
1004              
1005             # Iterate through workers
1006             my $workers = $minion->workers;
1007             while (my $info = $workers->next) {
1008             say "$info->{id}: $info->{host}";
1009             }
1010              
1011             These options are currently available:
1012              
1013             =over 2
1014              
1015             =item ids
1016              
1017             ids => ['23', '24']
1018              
1019             List only workers with these ids.
1020              
1021             =back
1022              
1023             These fields are currently available:
1024              
1025             =over 2
1026              
1027             =item id
1028              
1029             id => 22
1030              
1031             Worker id.
1032              
1033             =item host
1034              
1035             host => 'localhost'
1036              
1037             Worker host.
1038              
1039             =item jobs
1040              
1041             jobs => ['10023', '10024', '10025', '10029']
1042              
1043             Ids of jobs the worker is currently processing.
1044              
1045             =item notified
1046              
1047             notified => 784111777
1048              
1049             Epoch time worker sent the last heartbeat.
1050              
1051             =item pid
1052              
1053             pid => 12345
1054              
1055             Process id of worker.
1056              
1057             =item started
1058              
1059             started => 784111777
1060              
1061             Epoch time worker was started.
1062              
1063             =item status
1064              
1065             status => {queues => ['default', 'important']}
1066              
1067             Hash reference with whatever status information the worker would like to share.
1068              
1069             =back
1070              
1071             =head1 API
1072              
1073             This is the class hierarchy of the L distribution.
1074              
1075             =over 2
1076              
1077             =item * L
1078              
1079             =item * L
1080              
1081             =over 2
1082              
1083             =item * L
1084              
1085             =back
1086              
1087             =item * L
1088              
1089             =item * L
1090              
1091             =item * L
1092              
1093             =item * L
1094              
1095             =item * L
1096              
1097             =item * L
1098              
1099             =item * L
1100              
1101             =item * L
1102              
1103             =back
1104              
1105             =head1 BUNDLED FILES
1106              
1107             The L distribution includes a few files with different licenses that have been bundled for internal use.
1108              
1109             =head2 Minion Artwork
1110              
1111             Copyright (C) 2017, Sebastian Riedel.
1112              
1113             Licensed under the CC-SA License, Version 4.0 L.
1114              
1115             =head2 Bootstrap
1116              
1117             Copyright (C) 2011-2021 The Bootstrap Authors.
1118              
1119             Licensed under the MIT License, L.
1120              
1121             =head2 jQuery
1122              
1123             Copyright (C) jQuery Foundation.
1124              
1125             Licensed under the MIT License, L.
1126              
1127             =head2 D3.js
1128              
1129             Copyright (C) 2010-2016, Michael Bostock.
1130              
1131             Licensed under the 3-Clause BSD License, L.
1132              
1133             =head2 epoch.js
1134              
1135             Copyright (C) 2014 Fastly, Inc.
1136              
1137             Licensed under the MIT License, L.
1138              
1139             =head2 Font Awesome
1140              
1141             Copyright (C) Dave Gandy.
1142              
1143             Licensed under the MIT License, L, and the SIL OFL 1.1,
1144             L.
1145              
1146             =head2 moment.js
1147              
1148             Copyright (C) JS Foundation and other contributors.
1149              
1150             Licensed under the MIT License, L.
1151              
1152             =head1 AUTHORS
1153              
1154             =head2 Project Founder
1155              
1156             Sebastian Riedel, C.
1157              
1158             =head2 Contributors
1159              
1160             In alphabetical order:
1161              
1162             =over 2
1163              
1164             Andrey Khozov
1165              
1166             Andrii Nikitin
1167              
1168             Brian Medley
1169              
1170             Franz Skale
1171              
1172             Henrik Andersen
1173              
1174             Hubert "depesz" Lubaczewski
1175              
1176             Joel Berger
1177              
1178             Paul Williams
1179              
1180             Russell Shingleton
1181              
1182             Stefan Adams
1183              
1184             Stuart Skelton
1185              
1186             =back
1187              
1188             =head1 COPYRIGHT AND LICENSE
1189              
1190             Copyright (C) 2014-2024, Sebastian Riedel and others.
1191              
1192             This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version
1193             2.0.
1194              
1195             =head1 SEE ALSO
1196              
1197             L, L, L, L,
1198             L.
1199              
1200             =cut