Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018
view release on metacpan or search on metacpan
devdata/http_advent.perldancer.org_2018_16 view on Meta::CPAN
<p>With that in place, it was easy for our <code>queue_job()</code> method to throw an error if the developer tried to add a job to an invalid queue:</p>
<pre class="prettyprint">sub queue_job( $self, $args ) {
my $job_name = $args->{ name } or die "queue_job(): must define job name!";
my $guid = $args->{ guid } or die "queue_job(): must have GUID to process!";
my $title = $args->{ title } // $job_name;
my $queue = $args->{ queue } // 'default';
my $job_args = $args->{ job_args };
die "queue_job(): Invalid job queue '$queue' specified"
if $self->has_invalid_queues( $queue );
my %notes = ( title => $title, guid => $guid );
return $self->runner->enqueue( $job_name => $job_args =>
{ notes => \%notes, queue => $queue });
}</pre>
<h2><a name="creating_jobs"></a>Creating Jobs</h2>
<p>In our base model class (Moose-based), we would create an attribute for our job runner:</p>
<pre class="prettyprint">has 'job_runner' => (
is => 'ro',
isa => 'MyJob::JobQueue',
lazy => 1,
default => sub( $self ) { return MyJob::JobQueue->new->runner; },
);</pre>
<p>And in the models themselves, creating a new queueable task was as easy as:</p>
<pre class="prettyprint">$self->runner->add_task( InstantXML =>
sub( $job, $request_path, $guid, $company_db, $force, $die_on_error = 0 ) {
$job->note(
request_path => $request_path,
feed_id => 2098,
group => $company_db,
);
MyJob::Models::FooBar->new( request_path =>
$request_path )->generate_xml({
pdf_guid => $guid,
group => $company_db,
force => $force,
die_on_error => $die_on_error,
});
});</pre>
<h2><a name="running_jobs"></a>Running Jobs</h2>
<p>Starting a job from Dancer was super easy:</p>
<pre class="prettyprint">use Dancer2;
use MyJob::JobQueue;
sub job_queue {
return MyJob::JobQueue->new;
}
get '/my/api/route/:guid/:group/:force' => sub {
my $guid = route_parameters->get( 'guid' );
my $group = route_parameters->get( 'group' );
my $force = route_parameters->get( 'force' );
debug "GENERATING XML ONLY FOR $guid";
job_queue->queue_job({
name => "InstantXML",
guid => $guid,
title => "Instant XML Generator",
queue => 'InstantXML',
job_args => [ $self->request_path, $guid, $group, $force ],
});
}</pre>
<h2><a name="creating_and_configuring_the_job_queue_worker"></a>Creating and Configuring the Job Queue Worker</h2>
<p>We wanted to easily configure our Minions for all hosts and environments in one spot. Since we use a lot of YAML in Dancer, specifying the Minion configuration in YAML made a lot of sense
to us:</p>
<pre class="prettyprint"># What port does the dashboard listen on?
dashboard_port: 4000
# Add the rest later.
dashboards:
UNKNOWN: http://localhost:3000/
DEV: http://my.development.host.tld:8001/
# Hosts that have no entry assume the default configuration
default:
max_children: 4
queues:
- default
# Host-specific settings
jcrome-precision-3510:
max_children: 8
queues:
- default
- InstantXML
- PayrollXML
- ChangeRequest</pre>
<p>Our job queue workers look like:</p>
<pre class="prettyprint">#!/usr/bin/env perl
use MyJob::Base;
use MyJob::JobQueue;
use MyJob::Log4p;
use MyJob::Util::Logger;
use MyJob::Util::SysTools qw(get_hostname);
my $config = MyJob::Config->new->config;
my $hostconfig = get_hostconfig();
my $minion = MyJob::JobQueue->new;
my $worker = $minion->runner->worker;
my $log_eng = MyJob::Log4p->new({ logger_name => "Minion" });
my $logger = MyJob::Util::Logger->new->logger($log_eng);</pre>
<p>The above is mostly typical boilerplate for us. Read our configuration, and create a logger the worker can use.</p>
<p>Next, when a job is dequeued, we want to log that the worker picked up a job (needed for auditing purposes) and we alter the process name so if a process hangs, we know what that process
was attempting to run. If an unchecked exception occurs in a job, the worker will catch it and log it for us:</p>
<pre class="prettyprint">$worker->on( dequeue => sub( $worker, $job ) {
my $id = $job->id;
my $notes = $job->info->{ notes };
my $title = $notes->{ title };
( run in 0.430 second using v1.01-cache-2.11-cpan-39bf76dae61 )