mojolicious / minion

:octopus: Perl high performance job queue

Home Page:https://metacpan.org/release/Minion

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Allow registering subclass of Minion::Job as task

reinierk opened this issue · comments

It would be nice if it is possible to register a (homebrew) subclass of Minion::Job with add_task. This would allow to factor common code into the subclass for several similar tasks.

I've been thinking about doing something like this many times. But not sure yet what the best way to implement it would be.

Whatever we end up with, i do want using job classes to be as easy as $minion->add_task(foo => 'Some::FooJobClass').

I imagine a simple job class would look like this (translated from our basic example):

package MyApp::Task::PokeMojo;
use Mojo::Base 'Minion::Job', -signatures;

sub run ($self, @args) {
  $self->app->ua->get('mojolicious.org');
  $self->app->log->debug('We have poked mojolicious.org for a visitor');
});

1;

And then you'd register it in your app with:

$minion->add_task(poke_mojo => 'MyApp::Task::PokeMojo');

And enqueue it like any other job:

$minion->enqueue('poke_mojo');

Keeping the task a Minion::Job subclass will ensure that event based extensions (using the dequeue event from Minion::Worker) keep working. And give us access to all the lower level APIs in Minion::Job for new extensions on the task level.

@rabbiveesh There will definitely not be any routing shenanigans with name translation. Multiple methods are worth considering though.

$minion->add_task(poke_mojo => 'MyApp::Task::RandomStuff#poke_mojo');

If you want to factor out "base" code just stick your own base class between Minion::Job and PokeMojo

One problem i do see with multiple job methods per class is that extending Minion::Job would become rather tricky. So the feature will probably not be in the first proposal.

We'll start experimenting with the feature in the next Minion release. 3fd1014...8ac422a

Also, Role::Tiny exists

Minion::Job determines that "Run" is the run method. Fiddle with that if you want in your sub class. So I do not see that as any problem

I've tried using the subclass feature, and found it too rigid - one subclass per task doesn't seem to offer (to me at least) great advantages compared to registering tasks in a module.

I was looking for a way to add behaviours to tasks as in a question I'd asked on stackoverflow (https://stackoverflow.com/questions/65626783/setting-the-finish-event-on-a-mojolicious-minionjob).

It turned out that adding roles to tasks looks IMHO more fluent.

The way I did it was

  • a task builder function that takes a subref as argument, plus options
  • the task builder function wraps the subref in a job, adds roles to it
  • and returns another subref that runs the job

It works ok with two roles I built - a timeout that kills the job if it runs longer than a given time, and one that posts to a URL when the job is finished or failed

app->minion->add_task(some_task => task(sub { my $job = shift; sleep 5; $job->app->log->info('I am a task'); return 'Done!'; }, { roles => { '+Alerter' => { 'alert_on' => [qw/finished failed/ ] } } }));

I am an amateur - not a pro - and new to this so bear with me pls. My code kind of sucks right now, but I could share after a little cleanup it if it helps. I found this approach more inline with the general Mojolicious/MInion way of doing things, so I thought I'd share it, I hope it's ok.

The feature is done. More additions can be discussed in new issues.