Mojolicious-Plugin-Cron
view release on metacpan or search on metacpan
lib/Mojolicious/Plugin/Cron.pm view on Meta::CPAN
package Mojolicious::Plugin::Cron;
use Mojo::Base 'Mojolicious::Plugin';
use File::Spec;
use Fcntl ':flock';
use Mojo::File 'path';
use Mojo::IOLoop;
use Algorithm::Cron;
use Carp 'croak';
our $VERSION = "0.035";
use constant CRON_DIR => 'mojo_cron_';
my $crondir;
sub register {
my ($self, $app, $cronhashes) = @_;
croak "No schedules found" unless ref $cronhashes eq 'HASH';
# for *nix systems, getpwuid takes precedence
# for win systems or wherever getpwuid is not implemented,
# eval returns undef so getlogin takes precedence
$crondir
= path($app->config->{cron}{dir} // File::Spec->tmpdir)
->child(CRON_DIR . (eval { scalar getpwuid($<) } || getlogin || 'nobody'),
$app->mode);
Mojo::IOLoop->next_tick(sub {
if (ref((values %$cronhashes)[0]) eq 'CODE') {
# special case, plugin => 'mm hh dd ...' => sub {}
$self->_cron($app->moniker,
{crontab => (keys %$cronhashes)[0], code => (values %$cronhashes)[0]},
$app);
}
else {
$self->_cron($_, $cronhashes->{$_}, $app) for keys %$cronhashes;
}
});
}
sub _cron {
my ($self, $sckey, $cronhash, $app) = @_;
my $code = delete $cronhash->{code};
my $all_proc = delete $cronhash->{all_proc} // '';
my $test_key
= delete $cronhash->{__test_key}; # __test_key is for test case only
$sckey = $test_key // $sckey;
$cronhash->{base} //= 'local';
ref $cronhash->{crontab} eq ''
or croak "crontab parameter for schedule $sckey not a string";
ref $code eq 'CODE' or croak "code parameter for schedule $sckey is not CODE";
my $cron = Algorithm::Cron->new(%$cronhash);
my $time = time;
# $all_proc, $code, $cron, $sckey and $time will be part of the $task clojure
my $task;
$task = sub {
$time = $cron->next_time($time);
if (!$all_proc) {
}
Mojo::IOLoop->timer(
($time - time) => sub {
my $fire;
if ($all_proc) {
$fire = 1;
}
else {
my $dat = $crondir->child("$sckey.time");
my $sem = $crondir->child("$sckey.time.lock");
$crondir->make_path; # ensure path exists
my $handle_sem = $sem->open('>')
or croak "Cannot open semaphore file $!";
flock($handle_sem, LOCK_EX);
my $rtime = $1
if (-e $dat && $dat->slurp // '') =~ /(\d+)/; # do some untainting
$rtime //= '0';
if ($rtime != $time) {
$dat->spew($time);
$fire = 1;
}
undef $dat;
undef $sem; # unlock
( run in 2.522 seconds using v1.01-cache-2.11-cpan-98e64b0badf )