cron只运行一个Perl脚本实例

时间:2010-02-09 22:03:18

标签: perl cron

我需要定期运行cron的Perl脚本(〜每3-5分钟一次)。我想确保一次只运行一个Perl脚本实例,因此下一个周期将不会开始,直到前一个周期结束。可能/应该通过cron的一些内置功能实现,Perl还是我需要在脚本级别处理它?

我是Perl和cron的新手,所以感谢帮助和一般建议。

7 个答案:

答案 0 :(得分:14)

我总是使用File::NFSLock获得对脚本本身的独占锁定的好运。

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;

这与其他锁定文件建议相同,除了尝试获取锁定之外我不需要做任何事情。

答案 1 :(得分:11)

使用File::Pid将脚本的pid存储在一个文件中,脚本应该在开始时检查该文件,如果找到则中止。您可以在脚本完成时删除pid文件,但这不是真正必要的,因为您可以稍后检查以查看该进程ID是否仍然存在(这也将解释脚本意外中止的情况):

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;

答案 2 :(得分:11)

Sys::RunAlone模块可以很好地完成您想要的任务。只需添加

  use Sys::RunAlone;

靠近代码顶部。

答案 3 :(得分:3)

一种典型的方法是每个进程打开并锁定某个文件。然后,该过程将读取文件中包含的进程ID。

如果具有该ID的进程正在运行,则后来者会安静地退出。否则,新的胜利者将其进程ID(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;

答案 4 :(得分:1)

AFAIK perl没有这样的东西建设。在脚本完成时,您可以在启动应用程序并删除它时轻松创建临时文件。

答案 5 :(得分:1)

我一直使用它 - 小而简单 - 不依赖于任何模块,并且可以同时运行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;
}

答案 6 :(得分:-1)

鉴于频率,我通常会编写一个守护进程(服务器),它可以在作业运行(即sleep())之间等待,而不是尝试使用cron进行相当细粒度的访问。

如果有必要,在Unix / Linux系统上,您可以从/etc/inittab(或替换)运行它以确保它始终在运行,并在此过程中自动重新启动被终止或死亡。

已添加 :(并删除了一些不相关的内容)

始终存在(正在运行但主要是空闲的)守护进程方法的好处是可以消除cron自动启动脚本并发实例的可能性。

然而,它确实意味着您负责正确管理时序,例如在存在重叠的情况下(即,先前的运行仍在运行,而新的触发器发生)。这可以帮助您决定是使用分叉守护程序还是非分叉设计。在这种情况下,线程不提供任何优势,因此无需考虑其用法。

这并不能完全消除多个进程运行的可能性,但这是许多守护进程的常见问题。典型的解决方案是使用信号量,例如文件上的互斥锁,以防止第二个实例被运行。当过程结束时,文件锁被自动忘记,因此在异常终止(例如电源故障)的情况下,锁本身不需要清理。

使用Fcntl模块并使用带有sysopen标志(或O_EXCL)的Perl O_RDWR | O_CREAT | O_EXCL的方法是given by Greg Bacon。我要做的唯一区别是将独占锁定结合到sysopen调用中(即使用我建议的标志),然后删除当时冗余的flock调用。哦,我会遵循UNIX(&amp; Linux FHS)文件系统和/var/run/daemonname.pid的命名约定。

另一种方法是使用djb的daemontoolssimilar来“守护”任务。