Реализация таймаута в perl - PullRequest
       13

Реализация таймаута в perl

0 голосов
/ 14 января 2020

В следующем сценарии perl я намерен прервать выполнение сценария child_script.pl по истечении 1 часа. Тем не менее, logi c, похоже, не работает, так как сценарий все еще работает после указанного ограничения времени.

Есть какие-нибудь предположения, что я здесь делаю неправильно?

Я см. следующую документацию по реализации тайм-аута в perl: https://docstore.mik.ua/orelly/perl4/cook/ch16_22.htm

Он отлично работает для отдельной команды. Возможно ли, что у команды system есть проблема?

MY_CODE (parent_script.pl)

#!/usr/bin/perl

my $sys_cmd = " perl child_script.pl 2>&1 | tee logfile.txt \n";

print "INFO: Enter alarm..\n";
eval {
    local $SIG{ALRM} = sub { die "alarm clock restart" };
    alarm 3600;                   # schedule alarm in 1 hours
    eval {
            print "INFO: Run script.. \n";
            system ($sys_cmd);
    };
    alarm 0;                    # cancel the alarm
};
alarm 0;                        # race condition protection
die if $@ && $@ !~ /alarm clock restart/; # reraise
print "INFO: Exit alarm..\n";

Ответы [ 2 ]

2 голосов
/ 14 января 2020

Вы не истекаете время запуска сценария, который вы запустили; Вы устанавливаете будильник для текущего (родительского) скрипта. Вы должны были бы убить дочерний процесс (тот, который вы начали использовать system) из вашей тревоги- sub.

РЕДАКТИРОВАТЬ:

Если у вас есть /usr/bin/timeout (как это было бы в случае, если вы работаете на Linux), возможно, было бы более удобно использовать эту команду для обработки тайм-аута, вместо того, чтобы повторно реализовать logi c в Perl.

1 голос
/ 14 января 2020

Сигнал SIGALRM может отправляться или не отправляться во время выполнения вызова system, поэтому alarm может быть нестабильным. Это хороший вариант использования для тревоги бедного человека .

my $sys_cmd = "perl child_script.pl 2>&1 | tee logfile.txt";
# step 1. Start your long running command and capture it's process id
my $pid = fork();
if ($pid == 0) {
    exec($sys_cmd);
}
# step 2. Start another subprocess for the poor man's alarm.
my $time = 3600;
if (fork() == 0) {
    exec("$^X","-e","sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid");
}
# step 3. wait for first process to finish or be killed
my $c = waitpid $pid, 0;
if ($c & 128 == 9) {
    print "Process timed out and was killed by the poor man's alarm\n";
} else {
    print "Process finished without timing out.\n";
}

Сигнализация бедного человека запускается в отдельном процессе с двумя параметрами: $pid для мониторинга и $time ждать. Он периодически проверяет, жив ли отслеживаемый процесс. Если процесс больше не жив, тревога бедняка также прекращается, ничего не делая. После того, как прошло $time секунд, и отслеживаемый процесс все еще зависает, сигнал тревоги бедного человека посылает процессу сигнал уничтожения, который должен прекратить его.

...