crontab? File locks? docker???
Writing a simple cyclic thingy isn't that hard. Let's say you have a program that calculates the meaning of life, the universe and everything. It takes a varying time to execute. You want to call it every ten seconds or so, except when it takes longer to run. First, we need the program:
#!/usr/bin/env perl
use strict;
use warnings;
sleep(int(rand(10) + 5));
print "42\n";
Then we write a cyclic executive that keeps track of the run time of the external program (=the scheduler):
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw(time sleep);
my $cmd = "./meaningoflifetheuniverseandeverything.pl";
my $cycletime = 10;
while(1) {
my $starttime = time;
`$cmd`;
my $endtime = time;
my $timetaken = $endtime - $starttime;
if($timetaken >= $cycletime) {
print "Immediate restart\n";
next;
}
my $sleeptime = $cycletime - $timetaken;
print "Sleeping for $sleeptime\n";
sleep($sleeptime);
}
This effectively implements a simple "minimum cycle time" scheduler:
Sleeping for 0.986798048019409
Sleeping for 4.98646092414856
Sleeping for 3.98296499252319
Immediate restart
Immediate restart
Immediate restart
Immediate restart
If you want a more crontab like behaviour with start times aligned to specific times, you can use take the current time, calculate the modulos (division remainder) for the cycle time. Then calculate difference between that and a full cycle time interval how long to sleep. Like this:
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw(time sleep);
my $cmd = "./meaningoflifetheuniverseandeverything.pl";
my $cycletime = 10;
while(1) {
my $endtime = time;
my $sleeptime = $cycletime - ($endtime % $cycletime) - 1;
if($sleeptime) {
print "Sleeping for $sleeptime\n";
sleep($sleeptime);
}
`$cmd`;
}
Result:
Sleeping for 9
Sleeping for 5
Sleeping for 9
Sleeping for 6
Sleeping for 6
Sleeping for 7
This has a jitter of up to one second, but that should be acceptable enough, i think. Depending on your required time zone settings, you also might have to tweak the whole thing by about 37 seconds, plus/minus a couple of leap seconds every few years, something like this:
my $TAIoffset = -37;
...
my $endtime = time + $TAIoffset;
But that's probably overkill for most purposes.
perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
|