Run sub in perl script depending on time?

I have a perl script that runs like a daemon loop all the time. I want to run a subfunction in a perl script that is based on time (or a timer), so every 2 hours it will run this subfunction and continue its cycle. Iโ€™m thinking about getting an era and just checking it several times through the cycle, and as soon as it is more than 2 hours later, it will work as a subfunction. Is there a better way to do this in perl?

Thanks,
Lf4

+6
source share
3 answers

It depends on whether there should be 2 hours since the start of the last start of the subroutine START or from the end of the last execution.


1) If the last (2 hours between the end of the last subroutine and the start of a new one), the cespinoza solution is quite acceptable (the cycle is endless and call sleep(7200); after the subroutine is executed).

 my $timeout = 7200; while (1) { dostuff(); sleep($timeout); }; 

The only problem is that it cannot handle the case where dostuff() is executed forever, for example. stuck - to discuss why this is an important situation to consider and approaches to a solution, see below.


2) If the first (2 hours between the starting points), you have three options related to processing the execution time of the subroutine, which exceeds 2 hours [0] . Your 3 options, described in detail below, are intended for either:

2a) launches a new routine, while the old one continues to work (in parallel);

2b) to start a new routine AFTER the completion of the old;

2c) to start a new routine, but first stop the previous one.

2a, 2c options require you to set alarm() for 2 hours and differ in what happens when an alarm is triggered.

[0] NOTE. Since any routine is likely to require at least SOME resources from a PC, there is always at least a small chance that it will exceed 2 hours, so you need to choose one of these three options for processing such a scenario.


2a) Turn off every 2 hours, working in parallel with the old version, if not finished.

This parameter essentially implements the cron functionality.

At any time when you hear the word โ€œparallel,โ€ you are likely to abandon the process.

 my $timeout = 7200; while (1) { # Not tested! eval { local $SIG{ALRM} = sub { die "alarm\n" }; if (!defined($child_pid = fork())) { die "cannot fork: $!\n"; } elsif (!$child_pid) { # Child dostuff(); exit; } # Parent continues to sleep for 2 hours alarm $timeout; # You need it in case forking off take >2hrs sleep; # forever }; die unless $@ eq "alarm\n"; # propagate unexpected errors # We don't need to check if $@ is true due to forever sleep } 

2b) Go every 2 hours, if the old one is not finished, let him run until he finishes

This can be reformulated as a "starting task", if it ends faster than 2 hours, sleep for the rest "

 my $timeout = 7200; while (1) { my $start = time; dostuff(); my $end = time; my $lasted = $end - $start; if ($lasted < $timeout) { sleep($timeout - $lasted); } }; 

2c) Go every two hours, if the previous one is not finished, time and kill him

Whenever you see such logic, anxiety is obviously the answer.

 while (1) { my $finished = 0; eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm 7200; dostuff(); $finished = 1; sleep; # forever }; die unless $@ eq "alarm\n"; # propagate unexpected errors warn "Timed out!!!\n" unless $finished } 

PS As cespinoza noted, you need to somehow demonize the script (make sure that it will not be killed when you exit the shell that started it), either using Unix (for example, starting it as nohup), or Perlish means (search daemonize + Perl on Stackoverflow for the mechanics of this).

+9
source

Something like crontab would be best to do a similar job. However, if you want to run the Perl daemon, you will have to use some kind of event handler. Two options from the top of the head are POE and AnyEvent .

+2
source

You might want to check out Schedule :: Cron to plan and complete the task.

+1
source

Source: https://habr.com/ru/post/896008/


All Articles