User Tools

Site Tools


Planner Who Remembers

A single-threaded schedule executor who does not miss scheduled task due to employment.

I wrote it for DBdumper, Network dump/restore system

cron2.pl
#!/usr/bin/env perl
 
package aCron;
 
use strict;
use warnings;
use POSIX qw(strftime);
use Mojo::Util qw(dumper);
 
sub new {
    my $class = shift;
    my %quantums;
    my %minutes;
    my $self = {
        quantums => \%quantums,
        minutes => \%minutes,
        quantum_wide => 2,
        minute_wide => 60,
        horizon => 7,
    };
    bless $self, $class;
    return $self;
}
 
my %quantums;
my %minutes;
 
my $quantums = \%quantums;
my $minutes = \%minutes;
 
 
sub quantum_wide {
    my ($self, $wide) = @_;
    return $self->{quantum_wide} unless $wide;
    $self->{quantum_wide} = $wide;
    $self;
}
 
sub minute_wide {
    my ($self, $wide) = @_;
    return $self->{minute_wide} unless $wide;
    $self->{minute_wide} = $wide;
    $self;
}
 
sub horizon {
    my ($self, $wide) = @_;
    return $self->{horizon} unless $wide;
    $self->{horizon} = $wide;
    $self;
}
 
 
sub quantum {
    my ($self, $quantum, $status) = @_;
    return $self->{quantums}->{$quantum} unless $status;
    $self->{quantums}->{$quantum} = $status;
    $self;
}
 
sub minutes {
    my ($self, $min, $status) = @_;
    return $self->{minutes}->{$min} unless $status;
    $self->{minutes}->{$min} = $status;
    $self;
}
 
sub get_current_quantum {
    my $self = shift;
    int(time/$self->quantum_wide);
}
 
sub min {
    my ($self, $time) = @_;
    strftime("%M", localtime($time));
}
 
sub hour {
    my ($self, $time) = @_;
    strftime("%H", localtime($time));
}
 
sub wday {
    my ($self, $time) = @_;
    strftime("%u", localtime($time));
}
 
sub mday {
    my ($self, $time) = @_;
    strftime("%d", localtime($time));
}
 
sub expand {
    my ($self, $def, $start, $limit) = @_;
    $limit = 100 unless defined $limit;
    $start = 1 unless defined $start;
 
    $def =~ s/\s/,/g;
    $def =~ s/,,/,/g;
 
    my @list = split ',', $def;
    my @out;
    my %n;
    foreach my $sub (@list) {
        if (my ($num) = $sub =~ m/^(\d+)$/ ) {
                next if $num < $start;
                next if $num > $limit;
                push @out, $num unless $n{$num};
                $n{$num} = 1;
        }
        elsif (my ($begin, $end) = $sub =~ /^(\d+)[-. ]+(\d+)$/) {
            foreach my $num ($begin..$end) {
                next if $num < $start;
                next if $num > $limit;
                push @out, $num unless $n{$num};
                $n{$num} = 1;
            }
        }
        elsif (my ($inc) = $sub =~ /^[*]\/(\d+)$/) {
            my $num = $start-1;
            while ($num <= $limit - $inc) {
                $num += $inc;
                next if $num < $start;
                push @out, $num unless $n{$num};
                $n{$num} = 1;
            }
        }
        elsif ($sub =~ /^[*]$/) {
            my $num = $start;
            my $inc = 1;
            while ($num <= $limit) {
                next if $num < $start;
                next if $num > $limit;
                push @out, $num unless $n{$num};
                $n{$num} = 1;
                $num += $inc;
            }
        }
    }
    @out = sort {$a <=> $b} @out;
    return \@out
}
 
sub compact {
    my ($self, $list) = @_;
    my %n;
    my $out;
    foreach my $num (@{$list}) { $n{$num} = 1; }
    foreach my $num (sort { $a <=> $b } (keys %n)) {
        $out .= $num."-" if $n{$num + 1} && not $n{$num - 1};
        $out .= $num."," unless $n{$num+1};
    }
    $out =~ s/,$//;
    return $out;
}
 
sub match {
    my ($self, $num, $spec, $start, $end) = @_;
 
    my $list = $self->expand($spec, $start, $end);
    foreach my $rec (@$list) {
        return $rec if $num == $rec;
    }
    return undef;
}
 
1;
 
use strict;
use Mojo::Util qw(dumper);
use Mojo::IOLoop;
 
my $cr = aCron->new;
 
sub do_quantum {
 
    my $current_quantum = $cr->get_current_quantum;
    my $quantum_status = $cr->quantum($current_quantum) || 'undef';
 
    return 1 if $quantum_status eq 'done';
 
    # some do for this quantum 
    my $quantum_sec = $current_quantum * $cr->quantum_wide;
    my $current_min = int($quantum_sec / $cr->minute_wide);
 
    # the time machine
    foreach my $old_min (($current_min - $cr->horizon)..$current_min) {
 
        my $minute_status = $cr->minutes($old_min) || 'undef';
        next if ($minute_status eq 'done');
 
        my $time = $old_min * $cr->minute_wide;
 
        my $min = $cr->min($time);
        my $hour = $cr->hour($time);
        my $wday = $cr->wday($time);
        my $mday = $cr->mday($time);
 
        # some do for the past minute
        sleep int(rand 5);
 
        print "old_min=$old_min $hour:$min\n";
        $cr->minutes($old_min, 'done');
    }
    $cr->quantum($current_quantum, 'done');
}
 
my $loop = Mojo::IOLoop->singleton;
 
my $id = $loop->recurring(
    1 => \&do_quantum
);
 
$loop->start unless $loop->is_running;
 
#EOF

Out

Horizon (retro look) set to 7 minutes.

# date
Fri 12 Jan 2018 13:58:27 EET

# ./cron2.pl
old_min=25262631 13:51
old_min=25262632 13:52
old_min=25262633 13:53
old_min=25262634 13:54
old_min=25262635 13:55
old_min=25262636 13:56
old_min=25262637 13:57
old_min=25262638 13:58