Minion
view release on metacpan or search on metacpan
lib/Minion/Util.pm view on Meta::CPAN
}
# Hour
if (!$parsed->[1]{set}{$hour}) {
my $next = _next_value($parsed->[1]{values}, $hour);
$t
= defined $next ? timegm(0, 0, $next, $mday, $mon - 1, $year) : timegm(0, 0, 0, $mday, $mon - 1, $year) + 86400;
next;
}
# Minute
if (!$parsed->[0]{set}{$min}) {
my $next = _next_value($parsed->[0]{values}, $min);
$t
= defined $next
? timegm(0, $next, $hour, $mday, $mon - 1, $year)
: timegm(0, 0, $hour, $mday, $mon - 1, $year) + 3600;
next;
}
return $t;
}
croak qq{No matching time found for cron expression};
}
sub parse_cron {
my $expr = shift // '';
if ($expr =~ /^@/) {
croak qq{Unknown cron nickname "$expr"} unless exists $NICKNAMES{$expr};
$expr = $NICKNAMES{$expr};
}
my @fields = split /\s+/, $expr;
croak qq{Invalid cron expression "$expr": expected 5 fields} unless @fields == 5;
return [map { _parse_field($fields[$_], @{$FIELDS[$_]}) } 0 .. 4];
}
sub _day_match {
my ($parsed, $mday, $wday) = @_;
return 1 if $parsed->[2]{is_star} && $parsed->[4]{is_star};
return $parsed->[4]{set}{$wday} if $parsed->[2]{is_star};
return $parsed->[2]{set}{$mday} if $parsed->[4]{is_star};
return $parsed->[2]{set}{$mday} || $parsed->[4]{set}{$wday};
}
sub _next_value {
my ($values, $after) = @_;
for my $v (@$values) { return $v if $v >= $after }
return undef;
}
sub _parse_field {
my ($field, $name, $min, $max, $names) = @_;
my $is_star = $field eq '*' ? 1 : 0;
my %set;
for my $part (split /,/, $field) {
my ($range, $step) = split m{/}, $part, 2;
$step //= 1;
croak qq{Invalid step "$step" in $name field} unless $step =~ /^[1-9]\d*$/;
my ($a, $b);
if ($range eq '*') { ($a, $b) = ($min, $max) }
elsif ($range =~ /^(\w+)-(\w+)$/) { ($a, $b) = (_resolve($1, $name, $names), _resolve($2, $name, $names)) }
elsif ($range =~ /^(\w+)$/) { $a = $b = _resolve($1, $name, $names) }
else { croak qq{Invalid $name field "$part"} }
croak qq{Value out of range in $name field "$part" ($min-$max)} if $a < $min || $b > $max || $a > $b;
for (my $v = $a; $v <= $b; $v += $step) { $set{$v} = 1 }
}
# Day-of-week 7 is an alias for Sunday (0)
$set{0} = 1 if $name eq 'day-of-week' && delete $set{7};
return {set => \%set, values => [sort { $a <=> $b } keys %set], is_star => $is_star};
}
sub _resolve {
my ($value, $name, $names) = @_;
return $value + 0 if $value =~ /^\d+$/;
croak qq{Invalid name "$value" in $name field} unless $names && exists $names->{lc $value};
return $names->{lc $value};
}
1;
=encoding utf8
=head1 NAME
Minion::Util - Minion utility functions
=head1 SYNOPSIS
use Minion::Util qw(desired_tasks next_cron_time parse_cron);
=head1 DESCRIPTION
L<Minion::Util> provides utility functions for L<Minion>.
=head1 FUNCTIONS
L<Minion::Util> implements the following functions, which can be imported individually.
=head2 desired_tasks
my $desired_tasks = desired_tasks $limits, $available_tasks, $active_tasks;
Enforce limits and generate list of currently desired tasks.
# ['bar']
desired_tasks {foo => 2}, ['foo', 'bar'], ['foo', 'foo'];
=head2 next_cron_time
my $epoch = next_cron_time $expr, $from;
my $epoch = next_cron_time $parsed, $from;
( run in 0.873 second using v1.01-cache-2.11-cpan-71847e10f99 )