User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

perl:cron-w-rem [2020-02-15 00:57] (current)
Line 1: Line 1:
 +=====Planner Who Remembers=====
 +
 +A single-threaded schedule executor who does not miss scheduled task due to employment.
 +
 +I wrote it for [[:​dbdumper:​start]]
 +
 +
 +<code perl 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
 +</​code>​
 +
 +
 +===Out===
 +
 +Horizon (retro look) set to 7 minutes. ​
 +
 +<​code>​
 +# 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
 +</​code>​
 +