2010-02-09 17 views
20

द्वारा केवल एक पर्ल स्क्रिप्ट उदाहरण चलाना मुझे समय-समय पर क्रॉन द्वारा पर्ल स्क्रिप्ट चलाने की आवश्यकता है (~ हर 3-5 मिनट)। मैं यह सुनिश्चित करना चाहता हूं कि एक समय में केवल एक पर्ल स्क्रिप्ट इंस्टेंस चल रहा होगा, इसलिए अगला चक्र तब तक शुरू नहीं होगा जब तक कि पिछले एक समाप्त नहीं हो जाता है। क्रॉन, पर्ल या मुझे कुछ अंतर्निहित कार्यक्षमता द्वारा प्राप्त किया जा सकता है/क्या इसे स्क्रिप्ट स्तर पर इसे संभालने की आवश्यकता है?क्रॉन

मैं पर्ल और क्रॉन के लिए काफी नया हूं, इसलिए सहायता और सामान्य सिफारिशों की सराहना की जाती है।

+0

आप किस मंच के बारे में बात कर रहे हैं? * Nix? – weismat

+0

यह लिनक्स –

+0

पर चलाएगा http://blog.booking.com/highlander-daemons-without-daemons.html – stu42j

उत्तर

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; 

यह अन्य लॉक फ़ाइल सुझाव के रूप में ही की तरह है, सिवाय मैं ताला पाने के लिए प्रयास को छोड़कर कुछ भी करने की जरूरत नहीं है है।

+0

क्या यह काम करता है यदि स्क्रिप्ट में लेखन अनुमति नहीं है? – mob

+0

धन्यवाद! मुझे यह सबसे ज्यादा पसंद है, क्योंकि यह बहुत कॉम्पैक्ट है और फ़ाइल में कुछ भी नहीं लिख रहा है। –

+1

यह अभी भी एक लॉक फ़ाइल का उपयोग कर रहा है। अगर स्क्रिप्ट foo.pl है, तो यह डिफ़ॉल्ट रूप से foo.pl.NFSLock का उपयोग करता है। तो आपको निर्देशिका में लेखन अनुमति की आवश्यकता है। – oylenshpeegul

1

AFAIK perl में ऐसी कोई चीज़ बिल्डिन नहीं है। जब आप अपनी स्क्रिप्ट पूरी की जाती हैं, तो आप आसानी से एक टेम्पोरर फ़ाइल बना सकते हैं, जब आप अपना एप्लिकेशन शुरू करते हैं और इसे हटा देते हैं।

+2

क्षमा करें, अगर कुछ गलत हो जाता है तो मुझे बड़ी परेशानी होती है (मशीन पुनरारंभ) और फ़ाइल हटाई नहीं जाती है ... –

+0

कहने के लिए उचित है, लेकिन यदि आपकी स्क्रिप्ट चल रही है, तो मशीन को पुनरारंभ किया जाता है, तो आपको शायद परेशानी का सामना करना पड़ेगा (जब तक कि स्क्रिप्ट कुछ बेहद तुच्छ हो)। –

+0

स्क्रिप्ट रन के दौरान पुनरारंभ हो सकता है। लिपि डीबी लेनदेन का उपयोग कर रही है, इसलिए मुझे लगता है कि यह डेटा अखंडता को संरक्षित करने के लिए "जीवित" रह जाएगा। –

-1

आवृत्ति को देखते हुए मैं आम तौर पर एक डेमॉन (सर्वर) लिखता हूं जो कि काफी बढ़िया पहुंच के लिए क्रॉन का उपयोग करने की बजाय नौकरी चलाने (यानी sleep()) के बीच मूर्खता से इंतजार कर रहा है।

यदि आवश्यक हो, तो यूनिक्स/लिनक्स सिस्टम पर आप इसे /etc/inittab (या प्रतिस्थापन) से चला सकते हैं ताकि यह सुनिश्चित किया जा सके कि यह हमेशा चल रहा है, और प्रक्रिया में स्वचालित रूप से पुनरारंभ होता है या मर जाता है।

जोड़ा गया: (और कुछ अप्रासंगिक सामान निकाला गया)

हमेशा मौजूद (चल रहा है, लेकिन ज्यादातर बेकार) डेमॉन दृष्टिकोण स्क्रिप्ट की समवर्ती उदाहरणों की संभावना को नष्ट करने का लाभ मिलता है की जा रही स्वचालित रूप से क्रॉन द्वारा शुरू किया जा रहा है ।

लेकिन यह आप का क्या मतलब है (है, यानी पिछले एक रन अभी भी चल रहा है, जबकि एक नया ट्रिगर होता है) इस तरह के मामले में के रूप में सही ढंग से समय के प्रबंधन, की एक ओवरलैप है के लिए जिम्मेदार हैं। इससे आपको यह तय करने में मदद मिल सकती है कि फोर्किंग डिमन या गैर-फोर्किंग डिज़ाइन का उपयोग करना है या नहीं। थ्रेड इस परिदृश्य में कोई लाभ नहीं देते हैं, इसलिए उनके उपयोग पर विचार करने की कोई आवश्यकता नहीं है।

यह कई प्रक्रियाओं को चलाने की संभावना को पूरी तरह खत्म नहीं करता है, लेकिन यह कई डिमन्स के साथ एक आम समस्या है। एक सामान्य उदाहरण है कि एक दूसरे उदाहरण को चलाने से रोकने के लिए फ़ाइल पर परस्पर-अनन्य लॉक जैसे सेमफोर का उपयोग करना है। प्रक्रिया समाप्त होने पर फ़ाइल-लॉक स्वचालित रूप से भुला दिया जाता है, इसलिए असामान्य समाप्ति (जैसे बिजली विफलता) के मामले में लॉक के लिए कोई क्लीन-अप आवश्यक नहीं है।

एक दृष्टिकोण Fcntl मॉड्यूल का उपयोग कर, और एक O_EXCL ध्वज (या O_RDWR | O_CREAT | O_EXCL) के साथ एक पर्ल sysopen का उपयोग कर given by Greg Bacon था। केवल एक ही अंतर जो मैं करता हूं वह सिसोपेन कॉल में विशेष लॉकिंग को जोड़ता है (यानी मैंने सुझाए गए झंडे का उपयोग करें), और फिर अनावश्यक flock कॉल को हटा दें। ओह, और मैं यूनिक्स (& लिनक्स एफएचएस) फ़ाइल-सिस्टम और /var/run/daemonname.pid के नामकरण सम्मेलनों का पालन करता हूं।

एक अन्य दृष्टिकोण डीजेबी के daemontools या similar का उपयोग कार्य को "डिमननाइज़" करने के लिए करना होगा।

+0

एक डेमन चलाना एकाधिक चलने वाली स्क्रिप्ट समस्याओं को खत्म नहीं करता है .. किसी के लिए या किसी दूसरे के लिए गलती से दूसरे डेमॉन को शुरू करने का प्रयास करना आसान है। उस समस्या से निपटने के लिए आपको अभी भी एक पीआईडी ​​फाइल चाहिए। – mpounsett

3

प्रत्येक प्रक्रिया को एक निश्चित फ़ाइल को खोलने और लॉक करने के लिए एक सामान्य दृष्टिकोण है। फिर प्रक्रिया फ़ाइल में निहित प्रक्रिया आईडी पढ़ती है।

यदि उस आईडी के साथ कोई प्रक्रिया चल रही है, तो देर से आने वाला व्यक्ति चुपचाप बाहर निकलता है। अन्यथा, नया विजेता अपनी प्रक्रिया आईडी ($$ पर्ल में) लिखता है, जो हैंडल को बंद करता है (जो लॉक जारी करता है), और इसके व्यापार के बारे में जाता है।

उदाहरण नीचे कार्यान्वयन:

#! /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; 
11

उपयोग File::Pid एक फ़ाइल है, जो स्क्रिप्ट शुरू में लिए जाँच करनी चाहिए में स्क्रिप्ट के पीआईडी ​​की दुकान है, और अगर पाया निरस्त करने के लिए। जब स्क्रिप्ट पूरी हो जाती है तो आप पिडफाइल को हटा सकते हैं, लेकिन यह वास्तव में जरूरी नहीं है, क्योंकि आप यह देखने के लिए बाद में जांच सकते हैं कि यह प्रक्रिया आईडी अभी भी जिंदा है (जो आपकी स्क्रिप्ट अप्रत्याशित रूप से बंद होने पर मामलों के लिए भी जिम्मेदार होगी):

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; 
+0

मैं अपने स्रोत में कोई झुंड कॉल नहीं देखकर आश्चर्यचकित था! –

+0

@gbacon: एक पैच सबमिट करने के लिए स्वतंत्र महसूस करें :) – Ether

+0

मैं इस उत्तर की सिफारिश नहीं करता। आपके पास दौड़ की स्थिति है (चलने के बाद लिखना)। शायद यह कभी भी क्रॉन नौकरी में कोई मुद्दा नहीं होने वाला है, लेकिन बेहतर जवाब अभी भी बचा है क्योंकि बेहतर उत्तर हैं (स्वीकार्य देखें)। – Calimo

11

Sys :: RunAlone मॉड्यूल वह करता है जो आप बहुत अच्छी तरह से चाहते हैं। बस

use Sys::RunAlone; 

अपने कोड के शीर्ष के पास जोड़ें।

+0

+1 ACKNOWLEDGMENTS में पढ़ने के बाद +1: (धन्यवाद) Booking.com इस उत्पादन में भारी उपयोग करने और मुझे इस मॉड्यूल को बेहतर बनाने की अनुमति देने के लिए। – moodboom

1

मैंने हमेशा इसका उपयोग किया है - छोटे और सरल - किसी भी मॉड्यूल पर निर्भरता और विंडोज + लिनक्स दोनों काम करता है।

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; 
}