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   464446 use Mojo::Base 'Mojo::EventEmitter';
  2         22  
  2         13  
3              
4 2     2   2897 use Carp qw(croak);
  2         3  
  2         73  
5 2     2   11 use Config;
  2         2  
  2         63  
6 2     2   732 use Minion::Iterator;
  2         5  
  2         12  
7 2     2   801 use Minion::Job;
  2         5  
  2         15  
8 2     2   890 use Minion::Worker;
  2         4  
  2         13  
9 2     2   861 use Mojo::Date;
  2         5681  
  2         16  
10 2     2   60 use Mojo::IOLoop;
  2         4  
  2         7  
11 2     2   47 use Mojo::Loader qw(load_class);
  2         3  
  2         69  
12 2     2   10 use Mojo::Promise;
  2         3  
  2         9  
13 2     2   750 use Mojo::Server;
  2         2675  
  2         13  
14 2     2   64 use Mojo::Util qw(scope_guard steady_time);
  2         3  
  2         80  
15 2     2   747 use YAML::XS qw(Dump);
  2         4809  
  2         4076  
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 = '10.24';
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             =head2 class_for_task
374              
375             my $class = $minion->class_for_task('foo');
376              
377             Return job class for task. Note that this method is B and might change without warning!
378              
379             =head2 enqueue
380              
381             my $id = $minion->enqueue('foo');
382             my $id = $minion->enqueue(foo => [@args]);
383             my $id = $minion->enqueue(foo => [@args] => {priority => 1});
384              
385             Enqueue a new job with C state. Arguments get serialized by the L (often with L), so
386             you shouldn't send objects and be careful with binary data, nested data structures with hash and array references are
387             fine though.
388              
389             These options are currently available:
390              
391             =over 2
392              
393             =item attempts
394              
395             attempts => 25
396              
397             Number of times performing this job will be attempted, with a delay based on L after the first attempt,
398             defaults to C<1>.
399              
400             =item delay
401              
402             delay => 10
403              
404             Delay job for this many seconds (from now), defaults to C<0>.
405              
406             =item expire
407              
408             expire => 300
409              
410             Job is valid for this many seconds (from now) before it expires.
411              
412             =item lax
413              
414             lax => 1
415              
416             Existing jobs this job depends on may also have transitioned to the C state to allow for it to be processed,
417             defaults to C. Note that this option is B and might change without warning!
418              
419             =item notes
420              
421             notes => {foo => 'bar', baz => [1, 2, 3]}
422              
423             Hash reference with arbitrary metadata for this job that gets serialized by the L (often with
424             L), so you shouldn't send objects and be careful with binary data, nested data structures with hash and
425             array references are fine though.
426              
427             =item parents
428              
429             parents => [$id1, $id2, $id3]
430              
431             One or more existing jobs this job depends on, and that need to have transitioned to the state C before it
432             can be processed.
433              
434             =item priority
435              
436             priority => 5
437              
438             Job priority, defaults to C<0>. Jobs with a higher priority get performed first. Priorities can be positive or negative,
439             but should be in the range between C<100> and C<-100>.
440              
441             =item queue
442              
443             queue => 'important'
444              
445             Queue to put job in, defaults to C.
446              
447             =back
448              
449             =head2 foreground
450              
451             my $bool = $minion->foreground($id);
452              
453             Retry job in C queue, then perform it right away with a temporary worker in this process, very
454             useful for debugging.
455              
456             =head2 guard
457              
458             my $guard = $minion->guard('foo', 3600);
459             my $guard = $minion->guard('foo', 3600, {limit => 20});
460              
461             Same as L, but returns a scope guard object that automatically releases the lock as soon as the object is
462             destroyed, or C if aquiring the lock failed.
463              
464             # Only one job should run at a time (unique job)
465             $minion->add_task(do_unique_stuff => sub ($job, @args) {
466             return $job->finish('Previous job is still active')
467             unless my $guard = $minion->guard('fragile_backend_service', 7200);
468             ...
469             });
470              
471             # Only five jobs should run at a time and we try again later if necessary
472             $minion->add_task(do_concurrent_stuff => sub ($job, @args) {
473             return $job->retry({delay => 30})
474             unless my $guard = $minion->guard('some_web_service', 60, {limit => 5});
475             ...
476             });
477              
478             =head2 history
479              
480             my $history = $minion->history;
481              
482             Get history information for job queue.
483              
484             These fields are currently available:
485              
486             =over 2
487              
488             =item daily
489              
490             daily => [{epoch => 12345, finished_jobs => 95, failed_jobs => 2}, ...]
491              
492             Hourly counts for processed jobs from the past day.
493              
494             =back
495              
496             =head2 is_locked
497              
498             my $bool = $minion->is_locked('foo');
499              
500             Check if a lock with that name is currently active.
501              
502             =head2 job
503              
504             my $job = $minion->job($id);
505              
506             Get L object without making any changes to the actual job or return C if job does not exist.
507              
508             # Check job state
509             my $state = $minion->job($id)->info->{state};
510              
511             # Get job metadata
512             my $progress = $minion->job($id)->info->{notes}{progress};
513              
514             # Get job result
515             my $result = $minion->job($id)->info->{result};
516              
517             =head2 jobs
518              
519             my $jobs = $minion->jobs;
520             my $jobs = $minion->jobs({states => ['inactive']});
521              
522             Return L object to safely iterate through job information.
523              
524             # Iterate through jobs for two tasks
525             my $jobs = $minion->jobs({tasks => ['foo', 'bar']});
526             while (my $info = $jobs->next) {
527             say "$info->{id}: $info->{state}";
528             }
529              
530             # Remove all failed jobs from a named queue
531             my $jobs = $minion->jobs({states => ['failed'], queues => ['unimportant']});
532             while (my $info = $jobs->next) {
533             $minion->job($info->{id})->remove;
534             }
535              
536             # Count failed jobs for a task
537             say $minion->jobs({states => ['failed'], tasks => ['foo']})->total;
538              
539             These options are currently available:
540              
541             =over 2
542              
543             =item ids
544              
545             ids => ['23', '24']
546              
547             List only jobs with these ids.
548              
549             =item notes
550              
551             notes => ['foo', 'bar']
552              
553             List only jobs with one of these notes.
554              
555             =item queues
556              
557             queues => ['important', 'unimportant']
558              
559             List only jobs in these queues.
560              
561             =item states
562              
563             states => ['inactive', 'active']
564              
565             List only jobs in these states.
566              
567             =item tasks
568              
569             tasks => ['foo', 'bar']
570              
571             List only jobs for these tasks.
572              
573             =back
574              
575             These fields are currently available:
576              
577             =over 2
578              
579             =item args
580              
581             args => ['foo', 'bar']
582              
583             Job arguments.
584              
585             =item attempts
586              
587             attempts => 25
588              
589             Number of times performing this job will be attempted.
590              
591             =item children
592              
593             children => ['10026', '10027', '10028']
594              
595             Jobs depending on this job.
596              
597             =item created
598              
599             created => 784111777
600              
601             Epoch time job was created.
602              
603             =item delayed
604              
605             delayed => 784111777
606              
607             Epoch time job was delayed to.
608              
609             =item expires
610              
611             expires => 784111777
612              
613             Epoch time job is valid until before it expires.
614              
615             =item finished
616              
617             finished => 784111777
618              
619             Epoch time job was finished.
620              
621             =item id
622              
623             id => 10025
624              
625             Job id.
626              
627             =item lax
628              
629             lax => 0
630              
631             Existing jobs this job depends on may also have failed to allow for it to be processed.
632              
633             =item notes
634              
635             notes => {foo => 'bar', baz => [1, 2, 3]}
636              
637             Hash reference with arbitrary metadata for this job.
638              
639             =item parents
640              
641             parents => ['10023', '10024', '10025']
642              
643             Jobs this job depends on.
644              
645             =item priority
646              
647             priority => 3
648              
649             Job priority.
650              
651             =item queue
652              
653             queue => 'important'
654              
655             Queue name.
656              
657             =item result
658              
659             result => 'All went well!'
660              
661             Job result.
662              
663             =item retried
664              
665             retried => 784111777
666              
667             Epoch time job has been retried.
668              
669             =item retries
670              
671             retries => 3
672              
673             Number of times job has been retried.
674              
675             =item started
676              
677             started => 784111777
678              
679             Epoch time job was started.
680              
681             =item state
682              
683             state => 'inactive'
684              
685             Current job state, usually C, C, C or C.
686              
687             =item task
688              
689             task => 'foo'
690              
691             Task name.
692              
693             =item time
694              
695             time => 78411177
696              
697             Server time.
698              
699             =item worker
700              
701             worker => '154'
702              
703             Id of worker that is processing the job.
704              
705             =back
706              
707             =head2 lock
708              
709             my $bool = $minion->lock('foo', 3600);
710             my $bool = $minion->lock('foo', 3600, {limit => 20});
711              
712             Try to acquire a named lock that will expire automatically after the given amount of time in seconds. You can release
713             the lock manually with L to limit concurrency, or let it expire for rate limiting. For convenience you can
714             also use L to release the lock automatically, even if the job failed.
715              
716             # Only one job should run at a time (unique job)
717             $minion->add_task(do_unique_stuff => sub ($job, @args) {
718             return $job->finish('Previous job is still active')
719             unless $minion->lock('fragile_backend_service', 7200);
720             ...
721             $minion->unlock('fragile_backend_service');
722             });
723              
724             # Only five jobs should run at a time and we wait for our turn
725             $minion->add_task(do_concurrent_stuff => sub ($job, @args) {
726             sleep 1 until $minion->lock('some_web_service', 60, {limit => 5});
727             ...
728             $minion->unlock('some_web_service');
729             });
730              
731             # Only a hundred jobs should run per hour and we try again later if necessary
732             $minion->add_task(do_rate_limited_stuff => sub ($job, @args) {
733             return $job->retry({delay => 3600})
734             unless $minion->lock('another_web_service', 3600, {limit => 100});
735             ...
736             });
737              
738             An expiration time of C<0> can be used to check if a named lock could have been acquired without creating one.
739              
740             # Check if the lock "foo" could have been acquired
741             say 'Lock could have been acquired' unless $minion->lock('foo', 0);
742              
743             Or to simply check if a named lock already exists you can also use L.
744              
745             These options are currently available:
746              
747             =over 2
748              
749             =item limit
750              
751             limit => 20
752              
753             Number of shared locks with the same name that can be active at the same time, defaults to C<1>.
754              
755             =back
756              
757             =head2 new
758              
759             my $minion = Minion->new(Pg => 'postgresql://postgres@/test');
760             my $minion = Minion->new(Pg => Mojo::Pg->new);
761              
762             Construct a new L object.
763              
764             =head2 perform_jobs
765              
766             $minion->perform_jobs;
767             $minion->perform_jobs({queues => ['important']});
768              
769             Perform all jobs with a temporary worker, very useful for testing.
770              
771             # Longer version
772             my $worker = $minion->worker;
773             while (my $job = $worker->register->dequeue(0)) { $job->perform }
774             $worker->unregister;
775              
776             These options are currently available:
777              
778             =over 2
779              
780             =item id
781              
782             id => '10023'
783              
784             Dequeue a specific job.
785              
786             =item min_priority
787              
788             min_priority => 3
789              
790             Do not dequeue jobs with a lower priority.
791              
792             =item queues
793              
794             queues => ['important']
795              
796             One or more queues to dequeue jobs from, defaults to C.
797              
798             =back
799              
800             =head2 perform_jobs_in_foreground
801              
802             $minion->perform_jobs_in_foreground;
803             $minion->perform_jobs_in_foreground({queues => ['important']});
804              
805             Same as L, but all jobs are performed in the current process, without spawning new processes.
806              
807             =head2 repair
808              
809             $minion = $minion->repair;
810              
811             Repair worker registry and job queue if necessary.
812              
813             =head2 reset
814              
815             $minion = $minion->reset({all => 1});
816              
817             Reset job queue.
818              
819             These options are currently available:
820              
821             =over 2
822              
823             =item all
824              
825             all => 1
826              
827             Reset everything.
828              
829             =item locks
830              
831             locks => 1
832              
833             Reset only locks.
834              
835             =back
836              
837             =head2 result_p
838              
839             my $promise = $minion->result_p($id);
840             my $promise = $minion->result_p($id, {interval => 5});
841              
842             Return a L object for the result of a job. The state C will result in the promise being
843             C, and the state C in the promise being C. This operation can be cancelled by resolving
844             the promise manually at any time.
845              
846             # Enqueue job and receive the result at some point in the future
847             my $id = $minion->enqueue('foo');
848             $minion->result_p($id)->then(sub ($info) {
849             my $result = ref $info ? $info->{result} : 'Job already removed';
850             say "Finished: $result";
851             })->catch(sub ($info) {
852             say "Failed: $info->{result}";
853             })->wait;
854              
855             These options are currently available:
856              
857             =over 2
858              
859             =item interval
860              
861             interval => 5
862              
863             Polling interval in seconds for checking if the state of the job has changed, defaults to C<3>.
864              
865             =back
866              
867             =head2 stats
868              
869             my $stats = $minion->stats;
870              
871             Get statistics for the job queue.
872              
873             # Check idle workers
874             my $idle = $minion->stats->{inactive_workers};
875              
876             These fields are currently available:
877              
878             =over 2
879              
880             =item active_jobs
881              
882             active_jobs => 100
883              
884             Number of jobs in C state.
885              
886             =item active_locks
887              
888             active_locks => 100
889              
890             Number of active named locks.
891              
892             =item active_workers
893              
894             active_workers => 100
895              
896             Number of workers that are currently processing a job.
897              
898             =item delayed_jobs
899              
900             delayed_jobs => 100
901              
902             Number of jobs in C state that are scheduled to run at specific time in the future or have unresolved
903             dependencies.
904              
905             =item enqueued_jobs
906              
907             enqueued_jobs => 100000
908              
909             Rough estimate of how many jobs have ever been enqueued.
910              
911             =item failed_jobs
912              
913             failed_jobs => 100
914              
915             Number of jobs in C state.
916              
917             =item finished_jobs
918              
919             finished_jobs => 100
920              
921             Number of jobs in C state.
922              
923             =item inactive_jobs
924              
925             inactive_jobs => 100
926              
927             Number of jobs in C state.
928              
929             =item inactive_workers
930              
931             inactive_workers => 100
932              
933             Number of workers that are currently not processing a job.
934              
935             =item uptime
936              
937             uptime => 1000
938              
939             Uptime in seconds.
940              
941             =back
942              
943             =head2 unlock
944              
945             my $bool = $minion->unlock('foo');
946              
947             Release a named lock that has been previously acquired with L.
948              
949             =head2 worker
950              
951             my $worker = $minion->worker;
952              
953             Build L object. Note that this method should only be used to implement custom workers.
954              
955             # Use the standard worker with all its features
956             my $worker = $minion->worker;
957             $worker->status->{jobs} = 12;
958             $worker->status->{queues} = ['important'];
959             $worker->run;
960              
961             # Perform one job manually in a separate process
962             my $worker = $minion->repair->worker->register;
963             my $job = $worker->dequeue(5);
964             $job->perform;
965             $worker->unregister;
966              
967             # Perform one job manually in this process
968             my $worker = $minion->repair->worker->register;
969             my $job = $worker->dequeue(5);
970             if (my $err = $job->execute) { $job->fail($err) }
971             else { $job->finish }
972             $worker->unregister;
973              
974             # Build a custom worker performing multiple jobs at the same time
975             my %jobs;
976             my $worker = $minion->repair->worker->register;
977             do {
978             for my $id (keys %jobs) {
979             delete $jobs{$id} if $jobs{$id}->is_finished;
980             }
981             if (keys %jobs >= 4) { sleep 5 }
982             else {
983             my $job = $worker->dequeue(5);
984             $jobs{$job->id} = $job->start if $job;
985             }
986             } while keys %jobs;
987             $worker->unregister;
988              
989             =head2 workers
990              
991             my $workers = $minion->workers;
992             my $workers = $minion->workers({ids => [2, 3]});
993              
994             Return L object to safely iterate through worker information.
995              
996             # Iterate through workers
997             my $workers = $minion->workers;
998             while (my $info = $workers->next) {
999             say "$info->{id}: $info->{host}";
1000             }
1001              
1002             These options are currently available:
1003              
1004             =over 2
1005              
1006             =item ids
1007              
1008             ids => ['23', '24']
1009              
1010             List only workers with these ids.
1011              
1012             =back
1013              
1014             These fields are currently available:
1015              
1016             =over 2
1017              
1018             =item id
1019              
1020             id => 22
1021              
1022             Worker id.
1023              
1024             =item host
1025              
1026             host => 'localhost'
1027              
1028             Worker host.
1029              
1030             =item jobs
1031              
1032             jobs => ['10023', '10024', '10025', '10029']
1033              
1034             Ids of jobs the worker is currently processing.
1035              
1036             =item notified
1037              
1038             notified => 784111777
1039              
1040             Epoch time worker sent the last heartbeat.
1041              
1042             =item pid
1043              
1044             pid => 12345
1045              
1046             Process id of worker.
1047              
1048             =item started
1049              
1050             started => 784111777
1051              
1052             Epoch time worker was started.
1053              
1054             =item status
1055              
1056             status => {queues => ['default', 'important']}
1057              
1058             Hash reference with whatever status information the worker would like to share.
1059              
1060             =back
1061              
1062             =head1 API
1063              
1064             This is the class hierarchy of the L distribution.
1065              
1066             =over 2
1067              
1068             =item * L
1069              
1070             =item * L
1071              
1072             =over 2
1073              
1074             =item * L
1075              
1076             =back
1077              
1078             =item * L
1079              
1080             =item * L
1081              
1082             =item * L
1083              
1084             =item * L
1085              
1086             =item * L
1087              
1088             =item * L
1089              
1090             =item * L
1091              
1092             =item * L
1093              
1094             =back
1095              
1096             =head1 BUNDLED FILES
1097              
1098             The L distribution includes a few files with different licenses that have been bundled for internal use.
1099              
1100             =head2 Minion Artwork
1101              
1102             Copyright (C) 2017, Sebastian Riedel.
1103              
1104             Licensed under the CC-SA License, Version 4.0 L.
1105              
1106             =head2 Bootstrap
1107              
1108             Copyright (C) 2011-2021 The Bootstrap Authors.
1109              
1110             Licensed under the MIT License, L.
1111              
1112             =head2 D3.js
1113              
1114             Copyright (C) 2010-2016, Michael Bostock.
1115              
1116             Licensed under the 3-Clause BSD License, L.
1117              
1118             =head2 epoch.js
1119              
1120             Copyright (C) 2014 Fastly, Inc.
1121              
1122             Licensed under the MIT License, L.
1123              
1124             =head2 Font Awesome
1125              
1126             Copyright (C) Dave Gandy.
1127              
1128             Licensed under the MIT License, L, and the SIL OFL 1.1,
1129             L.
1130              
1131             =head2 moment.js
1132              
1133             Copyright (C) JS Foundation and other contributors.
1134              
1135             Licensed under the MIT License, L.
1136              
1137             =head1 AUTHORS
1138              
1139             =head2 Project Founder
1140              
1141             Sebastian Riedel, C.
1142              
1143             =head2 Contributors
1144              
1145             In alphabetical order:
1146              
1147             =over 2
1148              
1149             Andrey Khozov
1150              
1151             Andrii Nikitin
1152              
1153             Brian Medley
1154              
1155             Franz Skale
1156              
1157             Hubert "depesz" Lubaczewski
1158              
1159             Joel Berger
1160              
1161             Paul Williams
1162              
1163             Stefan Adams
1164              
1165             =back
1166              
1167             =head1 COPYRIGHT AND LICENSE
1168              
1169             Copyright (C) 2014-2022, Sebastian Riedel and others.
1170              
1171             This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version
1172             2.0.
1173              
1174             =head1 SEE ALSO
1175              
1176             L, L, L, L,
1177             L.
1178              
1179             =cut