1Minion(3) User Contributed Perl Documentation Minion(3)
2
3
4
6 Minion - Job queue
7
9 use Minion;
10
11 # Connect to backend
12 my $minion = Minion->new(Pg => 'postgresql://postgres@/test');
13
14 # Add tasks
15 $minion->add_task(something_slow => sub {
16 my ($job, @args) = @_;
17 sleep 5;
18 say 'This is a background worker process.';
19 });
20
21 # Enqueue jobs
22 $minion->enqueue(something_slow => ['foo', 'bar']);
23 $minion->enqueue(something_slow => [1, 2, 3] => {priority => 5});
24
25 # Perform jobs for testing
26 $minion->enqueue(something_slow => ['foo', 'bar']);
27 $minion->perform_jobs;
28
29 # Start a worker to perform up to 12 jobs concurrently
30 my $worker = $minion->worker;
31 $worker->status->{jobs} = 12;
32 $worker->run;
33
35 Minion is a high performance job queue for the Perl programming
36 language, with support for multiple named queues, priorities, delayed
37 jobs, job dependencies, job progress, job results, retries with
38 backoff, rate limiting, unique jobs, statistics, distributed workers,
39 parallel processing, autoscaling, remote control, Mojolicious
40 <https://mojolicious.org> admin ui, resource leak protection and
41 multiple backends (such as PostgreSQL <https://www.postgresql.org>).
42
43 Job queues allow you to process time and/or computationally intensive
44 tasks in background processes, outside of the request/response
45 lifecycle of web applications. Among those tasks you'll commonly find
46 image resizing, spam filtering, HTTP downloads, building tarballs,
47 warming caches and basically everything else you can imagine that's not
48 super fast.
49
51 You can use Minion as a standalone job queue or integrate it into
52 Mojolicious applications with the plugin Mojolicious::Plugin::Minion.
53
54 use Mojolicious::Lite;
55
56 plugin Minion => {Pg => 'postgresql://sri:s3cret@localhost/test'};
57
58 # Slow task
59 app->minion->add_task(poke_mojo => sub {
60 my $job = shift;
61 $job->app->ua->get('mojolicious.org');
62 $job->app->log->debug('We have poked mojolicious.org for a visitor');
63 });
64
65 # Perform job in a background worker process
66 get '/' => sub {
67 my $c = shift;
68 $c->minion->enqueue('poke_mojo');
69 $c->render(text => 'We will poke mojolicious.org for you soon.');
70 };
71
72 app->start;
73
74 Background worker processes are usually started with the command
75 Minion::Command::minion::worker, which becomes automatically available
76 when an application loads Mojolicious::Plugin::Minion.
77
78 $ ./myapp.pl minion worker
79
80 Jobs can be managed right from the command line with
81 Minion::Command::minion::job.
82
83 $ ./myapp.pl minion job
84
85 You can also add an admin ui to your application by loading the plugin
86 Mojolicious::Plugin::Minion::Admin. Just make sure to secure access
87 before making your application publically accessible.
88
89 # Make admin ui available under "/minion"
90 plugin 'Minion::Admin';
91
92 To manage background worker processes with systemd, you can use a unit
93 configuration file like this.
94
95 [Unit]
96 Description=My Mojolicious application workers
97 After=postgresql.service
98
99 [Service]
100 Type=simple
101 ExecStart=/home/sri/myapp/myapp.pl minion worker -m production
102 KillMode=process
103
104 [Install]
105 WantedBy=multi-user.target
106
107 Every job can fail or succeed, but not get lost, the system is
108 eventually consistent and will preserve job results for as long as you
109 like, depending on "remove_after". While individual workers can fail in
110 the middle of processing a job, the system will detect this and ensure
111 that no job is left in an uncertain state, depending on
112 "missing_after".
113
115 And as your application grows, you can move tasks into application
116 specific plugins.
117
118 package MyApp::Task::PokeMojo;
119 use Mojo::Base 'Mojolicious::Plugin';
120
121 sub register {
122 my ($self, $app) = @_;
123 $app->minion->add_task(poke_mojo => sub {
124 my $job = shift;
125 $job->app->ua->get('mojolicious.org');
126 $job->app->log->debug('We have poked mojolicious.org for a visitor');
127 });
128 }
129
130 1;
131
132 Which are loaded like any other plugin from your application.
133
134 # Mojolicious
135 $app->plugin('MyApp::Task::PokeMojo');
136
137 # Mojolicious::Lite
138 plugin 'MyApp::Task::PokeMojo';
139
141 This distribution also contains a great example application you can use
142 for inspiration. The link checker
143 <https://github.com/mojolicious/minion/tree/master/examples/linkcheck>
144 will show you how to integrate background jobs into well-structured
145 Mojolicious applications.
146
148 Minion inherits all events from Mojo::EventEmitter and can emit the
149 following new ones.
150
151 enqueue
152 $minion->on(enqueue => sub {
153 my ($minion, $id) = @_;
154 ...
155 });
156
157 Emitted after a job has been enqueued, in the process that enqueued it.
158
159 $minion->on(enqueue => sub {
160 my ($minion, $id) = @_;
161 say "Job $id has been enqueued.";
162 });
163
164 worker
165 $minion->on(worker => sub {
166 my ($minion, $worker) = @_;
167 ...
168 });
169
170 Emitted in the worker process after it has been created.
171
172 $minion->on(worker => sub {
173 my ($minion, $worker) = @_;
174 my $id = $worker->id;
175 say "Worker $$:$id started.";
176 });
177
179 Minion implements the following attributes.
180
181 app
182 my $app = $minion->app;
183 $minion = $minion->app(MyApp->new);
184
185 Application for job queue, defaults to a Mojo::HelloWorld object. Note
186 that this attribute is weakened.
187
188 backend
189 my $backend = $minion->backend;
190 $minion = $minion->backend(Minion::Backend::Pg->new);
191
192 Backend, usually a Minion::Backend::Pg object.
193
194 backoff
195 my $cb = $minion->backoff;
196 $minion = $minion->backoff(sub {...});
197
198 A callback used to calculate the delay for automatically retried jobs,
199 defaults to "(retries ** 4) + 15" (15, 16, 31, 96, 271, 640...), which
200 means that roughly 25 attempts can be made in 21 days.
201
202 $minion->backoff(sub {
203 my $retries = shift;
204 return ($retries ** 4) + 15 + int(rand 30);
205 });
206
207 missing_after
208 my $after = $minion->missing_after;
209 $minion = $minion->missing_after(172800);
210
211 Amount of time in seconds after which workers without a heartbeat will
212 be considered missing and removed from the registry by "repair",
213 defaults to 1800 (30 minutes).
214
215 remove_after
216 my $after = $minion->remove_after;
217 $minion = $minion->remove_after(86400);
218
219 Amount of time in seconds after which jobs that have reached the state
220 "finished" and have no unresolved dependencies will be removed
221 automatically by "repair", defaults to 172800 (2 days). It is not
222 recommended to set this value below 2 days.
223
224 tasks
225 my $tasks = $minion->tasks;
226 $minion = $minion->tasks({foo => sub {...}});
227
228 Registered tasks.
229
231 Minion inherits all methods from Mojo::EventEmitter and implements the
232 following new ones.
233
234 add_task
235 $minion = $minion->add_task(foo => sub {...});
236
237 Register a task.
238
239 # Job with result
240 $minion->add_task(add => sub {
241 my ($job, $first, $second) = @_;
242 $job->finish($first + $second);
243 });
244 my $id = $minion->enqueue(add => [1, 1]);
245 my $result = $minion->job($id)->info->{result};
246
247 broadcast
248 my $bool = $minion->broadcast('some_command');
249 my $bool = $minion->broadcast('some_command', [@args]);
250 my $bool = $minion->broadcast('some_command', [@args], [$id1, $id2, $id3]);
251
252 Broadcast remote control command to one or more workers.
253
254 # Broadcast "stop" command to all workers to kill job 10025
255 $minion->broadcast('stop', [10025]);
256
257 # Broadcast "kill" command to all workers to interrupt job 10026
258 $minion->broadcast('kill', ['INT', 10026]);
259
260 # Broadcast "jobs" command to pause worker 23
261 $minion->broadcast('jobs', [0], [23]);
262
263 enqueue
264 my $id = $minion->enqueue('foo');
265 my $id = $minion->enqueue(foo => [@args]);
266 my $id = $minion->enqueue(foo => [@args] => {priority => 1});
267
268 Enqueue a new job with "inactive" state. Arguments get serialized by
269 the "backend" (often with Mojo::JSON), so you shouldn't send objects
270 and be careful with binary data, nested data structures with hash and
271 array references are fine though.
272
273 These options are currently available:
274
275 attempts
276 attempts => 25
277
278 Number of times performing this job will be attempted, with a delay
279 based on "backoff" after the first attempt, defaults to 1.
280
281 delay
282 delay => 10
283
284 Delay job for this many seconds (from now), defaults to 0.
285
286 notes
287 notes => {foo => 'bar', baz => [1, 2, 3]}
288
289 Hash reference with arbitrary metadata for this job that gets
290 serialized by the "backend" (often with Mojo::JSON), so you shouldn't
291 send objects and be careful with binary data, nested data structures
292 with hash and array references are fine though.
293
294 parents
295 parents => [$id1, $id2, $id3]
296
297 One or more existing jobs this job depends on, and that need to have
298 transitioned to the state "finished" before it can be processed.
299
300 priority
301 priority => 5
302
303 Job priority, defaults to 0. Jobs with a higher priority get
304 performed first.
305
306 queue
307 queue => 'important'
308
309 Queue to put job in, defaults to "default".
310
311 foreground
312 my $bool = $minion->foreground($id);
313
314 Retry job in "minion_foreground" queue, then perform it right away with
315 a temporary worker in this process, very useful for debugging.
316
317 guard
318 my $guard = $minion->guard('foo', 3600);
319 my $guard = $minion->guard('foo', 3600, {limit => 20});
320
321 Same as "lock", but returns a scope guard object that automatically
322 releases the lock as soon as the object is destroyed, or "undef" if
323 aquiring the lock failed.
324
325 # Only one job should run at a time (unique job)
326 $minion->add_task(do_unique_stuff => sub {
327 my ($job, @args) = @_;
328 return $job->finish('Previous job is still active')
329 unless my $guard = $minion->guard('fragile_backend_service', 7200);
330 ...
331 });
332
333 # Only five jobs should run at a time and we try again later if necessary
334 $minion->add_task(do_concurrent_stuff => sub {
335 my ($job, @args) = @_;
336 return $job->retry({delay => 30})
337 unless my $guard = $minion->guard('some_web_service', 60, {limit => 5});
338 ...
339 });
340
341 history
342 my $history = $minion->history;
343
344 Get history information for job queue. Note that this method is
345 EXPERIMENTAL and might change without warning!
346
347 These fields are currently available:
348
349 daily
350 daily => [{epoch => 12345, finished_jobs => 95, failed_jobs => 2}, ...]
351
352 Hourly counts for processed jobs from the past day.
353
354 job
355 my $job = $minion->job($id);
356
357 Get Minion::Job object without making any changes to the actual job or
358 return "undef" if job does not exist.
359
360 # Check job state
361 my $state = $minion->job($id)->info->{state};
362
363 # Get job metadata
364 my $progress = $minion->$job($id)->info->{notes}{progress};
365
366 # Get job result
367 my $result = $minion->job($id)->info->{result};
368
369 lock
370 my $bool = $minion->lock('foo', 3600);
371 my $bool = $minion->lock('foo', 3600, {limit => 20});
372
373 Try to acquire a named lock that will expire automatically after the
374 given amount of time in seconds. You can release the lock manually with
375 "unlock" to limit concurrency, or let it expire for rate limiting. For
376 convenience you can also use "guard" to release the lock automatically,
377 even if the job failed.
378
379 # Only one job should run at a time (unique job)
380 $minion->add_task(do_unique_stuff => sub {
381 my ($job, @args) = @_;
382 return $job->finish('Previous job is still active')
383 unless $minion->lock('fragile_backend_service', 7200);
384 ...
385 $minion->unlock('fragile_backend_service');
386 });
387
388 # Only five jobs should run at a time and we wait for our turn
389 $minion->add_task(do_concurrent_stuff => sub {
390 my ($job, @args) = @_;
391 sleep 1 until $minion->lock('some_web_service', 60, {limit => 5});
392 ...
393 $minion->unlock('some_web_service');
394 });
395
396 # Only a hundred jobs should run per hour and we try again later if necessary
397 $minion->add_task(do_rate_limited_stuff => sub {
398 my ($job, @args) = @_;
399 return $job->retry({delay => 3600})
400 unless $minion->lock('another_web_service', 3600, {limit => 100});
401 ...
402 });
403
404 An expiration time of 0 can be used to check if a named lock already
405 exists without creating one.
406
407 # Check if the lock "foo" already exists
408 say 'Lock exists' unless $minion->lock('foo', 0);
409
410 These options are currently available:
411
412 limit
413 limit => 20
414
415 Number of shared locks with the same name that can be active at the
416 same time, defaults to 1.
417
418 new
419 my $minion = Minion->new(Pg => 'postgresql://postgres@/test');
420 my $minion = Minion->new(Pg => Mojo::Pg->new);
421
422 Construct a new Minion object.
423
424 perform_jobs
425 $minion->perform_jobs;
426 $minion->perform_jobs({queues => ['important']});
427
428 Perform all jobs with a temporary worker, very useful for testing.
429
430 # Longer version
431 my $worker = $minion->worker;
432 while (my $job = $worker->register->dequeue(0)) { $job->perform }
433 $worker->unregister;
434
435 These options are currently available:
436
437 queues
438 queues => ['important']
439
440 One or more queues to dequeue jobs from, defaults to "default".
441
442 repair
443 $minion = $minion->repair;
444
445 Repair worker registry and job queue if necessary.
446
447 reset
448 $minion = $minion->reset;
449
450 Reset job queue.
451
452 result_p
453 my $promise = $minion->result_p($id);
454 my $promise = $minion->result_p($id, {interval => 5});
455
456 Return a Mojo::Promise object for the result of a job. The state
457 "finished" will result in the promise being "fullfilled", and the state
458 "failed" in the promise being "rejected". This operation can be
459 cancelled by resolving the promise manually at any time. Note that this
460 method is EXPERIMENTAL and might change without warning!
461
462 # Enqueue job and receive the result at some point in the future
463 my $id = $minion->enqueue('foo');
464 $minion->result_p($id)->then(sub {
465 my $info = shift;
466 my $result = ref $info ? $info->{result} : 'Job already removed';
467 say "Finished: $result";
468 })->catch(sub {
469 my $info = shift;
470 say "Failed: $info->{result}";
471 })->wait;
472
473 These options are currently available:
474
475 interval
476 interval => 5
477
478 Polling interval in seconds for checking if the state of the job has
479 changed, defaults to 3.
480
481 stats
482 my $stats = $minion->stats;
483
484 Get statistics for the job queue.
485
486 # Check idle workers
487 my $idle = $minion->stats->{inactive_workers};
488
489 These fields are currently available:
490
491 active_jobs
492 active_jobs => 100
493
494 Number of jobs in "active" state.
495
496 active_locks
497 active_locks => 100
498
499 Number of active named locks.
500
501 active_workers
502 active_workers => 100
503
504 Number of workers that are currently processing a job.
505
506 delayed_jobs
507 delayed_jobs => 100
508
509 Number of jobs in "inactive" state that are scheduled to run at
510 specific time in the future or have unresolved dependencies. Note
511 that this field is EXPERIMENTAL and might change without warning!
512
513 enqueued_jobs
514 enqueued_jobs => 100000
515
516 Rough estimate of how many jobs have ever been enqueued. Note that
517 this field is EXPERIMENTAL and might change without warning!
518
519 failed_jobs
520 failed_jobs => 100
521
522 Number of jobs in "failed" state.
523
524 finished_jobs
525 finished_jobs => 100
526
527 Number of jobs in "finished" state.
528
529 inactive_jobs
530 inactive_jobs => 100
531
532 Number of jobs in "inactive" state.
533
534 inactive_workers
535 inactive_workers => 100
536
537 Number of workers that are currently not processing a job.
538
539 uptime
540 uptime => 1000
541
542 Uptime in seconds.
543
544 unlock
545 my $bool = $minion->unlock('foo');
546
547 Release a named lock that has been previously acquired with "lock".
548
549 worker
550 my $worker = $minion->worker;
551
552 Build Minion::Worker object.
553
554 # Use the standard worker with all its features
555 my $worker = $minion->worker;
556 $worker->status->{jobs} = 12;
557 $worker->status->{queues} = ['important'];
558 $worker->run;
559
560 # Perform one job manually in a separate process
561 my $worker = $minion->repair->worker->register;
562 my $job = $worker->dequeue(5);
563 $job->perform;
564 $worker->unregister;
565
566 # Perform one job manually in this process
567 my $worker = $minion->repair->worker->register;
568 my $job = $worker->dequeue(5);
569 if (my $err = $job->execute) { $job->fail($err) }
570 else { $job->finish }
571 $worker->unregister;
572
573 # Build a custom worker performing multiple jobs at the same time
574 my %jobs;
575 my $worker = $minion->repair->worker->register;
576 do {
577 for my $id (keys %jobs) {
578 delete $jobs{$id} if $jobs{$id}->is_finished;
579 }
580 if (keys %jobs >= 4) { sleep 5 }
581 else {
582 my $job = $worker->dequeue(5);
583 $jobs{$job->id} = $job->start if $job;
584 }
585 } while keys %jobs;
586 $worker->unregister;
587
589 This is the class hierarchy of the Minion distribution.
590
591 · Minion
592
593 · Minion::Backend
594
595 · Minion::Backend::Pg
596
597 · Minion::Command::minion
598
599 · Minion::Command::minion::job
600
601 · Minion::Command::minion::worker
602
603 · Minion::Job
604
605 · Minion::Worker
606
607 · Mojolicious::Plugin::Minion
608
609 · Mojolicious::Plugin::Minion::Admin
610
612 The Minion distribution includes a few files with different licenses
613 that have been bundled for internal use.
614
615 Minion Artwork
616 Copyright (C) 2017, Sebastian Riedel.
617
618 Licensed under the CC-SA License, Version 4.0
619 <http://creativecommons.org/licenses/by-sa/4.0>.
620
621 Bootstrap
622 Copyright (C) 2011-2018 The Bootstrap Authors.
623
624 Licensed under the MIT License,
625 <http://creativecommons.org/licenses/MIT>.
626
627 D3.js
628 Copyright (C) 2010-2016, Michael Bostock.
629
630 Licensed under the 3-Clause BSD License,
631 <https://opensource.org/licenses/BSD-3-Clause>.
632
633 epoch.js
634 Copyright (C) 2014 Fastly, Inc.
635
636 Licensed under the MIT License,
637 <http://creativecommons.org/licenses/MIT>.
638
639 Font Awesome
640 Copyright (C) Dave Gandy.
641
642 Licensed under the MIT License,
643 <http://creativecommons.org/licenses/MIT>, and the SIL OFL 1.1,
644 <http://scripts.sil.org/OFL>.
645
646 moment.js
647 Copyright (C) JS Foundation and other contributors.
648
649 Licensed under the MIT License,
650 <http://creativecommons.org/licenses/MIT>.
651
652 popper.js
653 Copyright (C) Federico Zivolo 2017.
654
655 Licensed under the MIT License,
656 <http://creativecommons.org/licenses/MIT>.
657
659 Sebastian Riedel, "sri@cpan.org".
660
662 In alphabetical order:
663
664 Andrey Khozov
665
666 Brian Medley
667
668 Hubert "depesz" Lubaczewski
669
670 Joel Berger
671
672 Paul Williams
673
674 Stefan Adams
675
677 Copyright (C) 2014-2019, Sebastian Riedel and others.
678
679 This program is free software, you can redistribute it and/or modify it
680 under the terms of the Artistic License version 2.0.
681
683 <https://github.com/mojolicious/minion>, Mojolicious::Guides,
684 <https://mojolicious.org>.
685
686
687
688perl v5.28.1 2019-02-03 Minion(3)