Подтвердить что ты не робот

Запуск только одного экземпляра Perl script cron

Мне нужно запустить Perl script cron периодически (~ каждые 3-5 минут). Я хочу гарантировать, что только один экземпляр Perl script будет запущен за один раз, поэтому следующий цикл не начнется, пока предыдущий не будет завершен. Может ли/быть достигнуто с помощью некоторых встроенных функций cron, Perl или мне нужно обрабатывать его на уровне script?

Я новичок в Perl и cron, поэтому мне помогают рекомендации и общие рекомендации.

4b9b3361

Ответ 1

Мне всегда удавалось использовать File:: NFSLock, чтобы получить эксклюзивную блокировку самого script.

use Fcntl qw(LOCK_EX LOCK_NB);
use File::NFSLock;

# Try to get an exclusive lock on myself.
my $lock = File::NFSLock->new($0, LOCK_EX|LOCK_NB);
die "$0 is already running!\n" unless $lock;

Это похоже на другие предложения блокировки, за исключением того, что мне не нужно ничего делать, кроме попытки получить блокировку.

Ответ 2

Используйте File::Pid для хранения файла script pid в файле, который script должен проверить в начале, и прервать, если найдено. Вы можете удалить pidfile, когда выполняется script, но это действительно не необходимо, поскольку вы можете просто проверить позже, чтобы узнать, жив ли этот идентификатор процесса (который также учитывает случаи, когда ваш script прерывается неожиданно)

use strict;
use warnings;
use File::Pid;

my $pidfile = File::Pid->new({file => /var/run/myscript});
exit if $pidfile->running();

$pidfile->write();

# ... rest of script...

# end of script
$pidfile->remove();
exit;

Ответ 3

Модуль Sys:: RunAlone делает то, что вы хотите очень красиво. Просто добавьте

  use Sys::RunAlone;

в верхней части вашего кода.

Ответ 4

Типичный подход заключается в том, чтобы каждый процесс открывал и блокировал определенный файл. Затем процесс считывает идентификатор процесса, содержащийся в файле.

Если процесс с этим идентификатором запущен, опоздавший выходит тихо. В противном случае новый победитель записывает свой идентификатор процесса ($$ в Perl) в pidfile, закрывает дескриптор (который освобождает блокировку) и идет о его бизнесе.

Пример реализации ниже:

#! /usr/bin/perl

use warnings;
use strict;

use Fcntl qw/ :DEFAULT :flock :seek /;

my $PIDFILE = "/tmp/my-program.pid";
sub take_lock {
  sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT or die "$0: open $PIDFILE: $!";
  flock $fh => LOCK_EX                       or die "$0: flock $PIDFILE: $!";

  my $pid = <$fh>;
  if (defined $pid) {
    chomp $pid;
    if (kill 0 => $pid) {
      close $fh;
      exit 1;
    }
  }
  else {
    die "$0: readline $PIDFILE: $!" if $!;
  }

  sysseek  $fh, 0, SEEK_SET or die "$0: sysseek $PIDFILE: $!";
  truncate $fh, 0           or die "$0: truncate $PIDFILE: $!";
  print    $fh "$$\n"       or die "$0: print $PIDFILE: $!";
  close    $fh              or die "$0: close: $!";
}

take_lock;
print "$0: [$$] running...\n";
sleep 2;

Ответ 5

У AFAIK perl нет такой вещи buildin. Вы можете легко создать временный файл при запуске приложения и удалить его, когда будет выполнен script.

Ответ 6

Я всегда использовал это - маленькое и простое - никакой зависимости от любого модуля и не работал как с Windows + Linux.

use Fcntl ':flock';                    

### Check to make sure there is only one instance ###
open SELF, "< $0" or die("Cannot run two instances of this program");
unless ( flock SELF, LOCK_EX | LOCK_NB ) {
    print "You cannot run two instances of this program , a process is still running";
    exit 1;
}

Ответ 7

Учитывая частоту, я обычно пишу демона (сервера), который прекрасно ждет без изменений между запусками задания (т.е. sleep()), а не пытается использовать cron для довольно мелкозернистого доступа.

Если необходимо, в системах Unix/Linux вы можете запустить его из /etc/inittab (или замены), чтобы гарантировать, что он всегда работает и автоматически перезапускается в процессе, убивается или умирает.

Добавлено: (и некоторые ненужные вещи удалены)

Всегда присутствующий (работает, но в основном простой) подход демона имеет преимущество в устранении возможности одновременного запуска параллельных экземпляров script с помощью cron.

Однако это означает, что вы отвечаете за правильное управление временем, например, в случае перекрытия (т.е. предыдущий запуск все еще выполняется, в то время как возникает новый триггер). Это может помочь вам решить, следует ли использовать демон forking или дизайн без forking. В этом случае нити не дают никаких преимуществ, поэтому нет необходимости рассматривать их использование.

Это не полностью исключает возможность выполнения нескольких процессов, но это общая проблема со многими демонами. Типичным решением является использование семафора, такого как взаимоисключающая блокировка файла, чтобы предотвратить запуск второго экземпляра. Блокировка файла автоматически забывается, когда процесс завершается, поэтому в случае ненормального завершения (например, сбой питания) очистка не требуется самой блокировки.

Подход с использованием модуля Fcntl и использование Perl sysopen с флагом O_EXCL (или O_RDWR | O_CREAT | O_EXCL) был данный Грегом Бэконом. Единственные различия, которые я хотел бы сделать, - это сочетание исключительной блокировки в вызове sysopen (т.е. Использование предложенных флагов) и удаление избыточного вызова flock. О, и я буду следовать файловой системе UNIX (& Linux FHS) и соглашениям об именах /var/run/daemonname.pid.

Другим подходом было бы использовать djb daemontools или аналогичный для "daemonize" задание.