我需要定期運行Perl腳本(〜每3-5分鐘)。我想確保一次只能運行一個Perl腳本實例,所以下一個循環在上一個循環完成之前不會啓動。可以/應該通過cron,Perl的某些內置功能來實現,還是我需要在腳本級別處理它?由cron運行只有一個Perl腳本實例
我對Perl和cron相當陌生,所以需要幫助和一般建議。
我需要定期運行Perl腳本(〜每3-5分鐘)。我想確保一次只能運行一個Perl腳本實例,所以下一個循環在上一個循環完成之前不會啓動。可以/應該通過cron,Perl的某些內置功能來實現,還是我需要在腳本級別處理它?由cron運行只有一個Perl腳本實例
我對Perl和cron相當陌生,所以需要幫助和一般建議。
我一直使用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;
這與其他鎖文件建議的排序方式相同,只是除了嘗試獲取鎖之外,沒有其他任何操作。
如果腳本沒有寫入權限,這是否工作? – mob 2010-02-10 05:45:45
謝謝!我最喜歡它,因爲它非常緊湊,不需要寫任何文件。 – 2010-02-10 09:16:57
它仍在使用鎖定文件。如果腳本是foo.pl,則默認使用foo.pl.NFSLock。所以你需要對目錄有寫權限。 – oylenshpeegul 2010-02-10 13:01:30
AFAIK perl沒有這樣的東西buildin。當您啓動應用程序並刪除它時,您可以輕鬆創建一個臨時文件,當您的腳本完成時。
對不起,我預見帶來很大麻煩,如果出現錯誤(機器重新啓動)和文件不會被刪除運行... – 2010-02-09 22:13:02
公平地說,但是如果機器在腳本運行時重新啓動,那麼您可能會遇到麻煩(除非腳本做了一些非常微不足道的事情)。 – 2010-02-09 22:33:07
在腳本運行期間可能發生重新啓動。該腳本使用數據庫事務,所以我認爲它會「重新生存」重新啓動,以保持數據的完整性。 – 2010-02-09 22:40:58
鑑於頻率,我通常會編寫一個守護進程(服務器),在作業運行之間很好地等待(即sleep()
),而不是嘗試使用cron進行相當精細的訪問。
如果有必要,在Unix/Linux系統上,您可以從/etc/inittab
(或更換)運行它,以確保它始終運行,並且在進程死亡或死亡時自動重啓。
新增:(和一些無關緊要的東西去掉)
總是存在的(運行,但大多是空閒的)進程的方法具有消除腳本的併發實例的可能性的好處正在被由cron自動啓動。
但是,這意味着您有責任正確管理計時,例如在存在重疊的情況下(例如,上次運行仍在運行,而新的觸發器發生)。這可以幫助您決定是使用分叉守護進程還是非分叉設計。線程在這種情況下不提供任何優勢,因此不需要考慮它們的用法。
這並不能完全消除多進程運行的可能性,但這是許多守護進程的常見問題。典型的解決方案是在文件上使用諸如互斥鎖的信號量,以防止運行第二個實例。當進程結束時,文件鎖自動被遺忘,因此在異常終止(例如電源故障)的情況下,鎖自身不需要清理。
使用FCNTL模塊,以及使用一個Perl sysopen
與O_EXCL
標誌(或O_RDWR | O_CREAT | O_EXCL
)一種方法是given by Greg Bacon。我唯一的區別是將獨佔鎖定結合到sysopen調用中(即使用我建議的標誌),然後刪除當時多餘的調用。哦,我會遵循UNIX(& Linux FHS)文件系統和命名約定/var/run/daemonname.pid
。
另一種方法是使用djb的daemontools或similar來「守護」任務。
運行守護進程並不能消除多個運行腳本問題..對於某人或某事偶然嘗試啓動第二個守護進程很容易。你仍然需要一個PID文件來處理這個問題。 – mpounsett 2015-02-25 21:48:59
一個典型的方法是每個進程打開並鎖定某個文件。然後該進程讀取文件中包含的進程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;
使用File::Pid存儲腳本的PID的文件,該腳本應在開始時檢查,如果發現異常中止。當劇本完成後,你可以刪除pidfile進程文件,但它不是真正需要的,你可以簡單地檢查後,看是否該進程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;
Sys :: RunAlone模塊可以很好地完成你想要的功能。只需添加
use Sys::RunAlone;
靠近代碼頂部。
+1。 – moodboom 2015-02-03 22:54:00
我一直使用這個 - 小而簡單 - 不依賴於任何模塊,並且可以同時運行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;
}
哪個平臺,你在說什麼? * nix中? – weismat 2010-02-09 22:27:46
它會在Linux上 – 2010-02-09 22:32:31
http://blog.booking.com/highlander-daemons-without-daemons.html – stu42j 2014-04-18 17:22:21