我需要定期运行cron的Perl脚本(〜每3-5分钟一次)。我想确保一次只运行一个Perl脚本实例,因此下一个周期将不会开始,直到前一个周期结束。可能/应该通过cron的一些内置功能实现,Perl还是我需要在脚本级别处理它?
我是Perl和cron的新手,所以感谢帮助和一般建议。
答案 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)
答案 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的daemontools或similar来“守护”任务。