डुप्लिकेट क्रोन नौकरियों को रोकें


92

मैंने हर मिनट चलाने के लिए एक क्रॉन जॉब निर्धारित की है लेकिन कभी-कभी स्क्रिप्ट खत्म होने में एक मिनट से अधिक समय लगता है और मैं नहीं चाहता कि जॉब्स एक-दूसरे के ऊपर "स्टैकिंग" शुरू करें। मुझे लगता है कि यह एक संक्षिप्त समस्या है - यानी स्क्रिप्ट निष्पादन को पारस्परिक रूप से अनन्य होना चाहिए।

समस्या को हल करने के लिए मैंने स्क्रिप्ट को किसी विशेष फ़ाइल (" लॉकफाइल.टेक्स्ट ") के अस्तित्व के लिए बनाया था और अगर यह मौजूद है या touchनहीं तो बाहर निकलें । लेकिन यह एक बहुत ही घटिया सेमाफोर है! क्या कोई सबसे अच्छा अभ्यास है जिसके बारे में मुझे पता होना चाहिए? क्या मुझे इसके बजाय डेमन लिखना चाहिए था?

जवाबों:


118

ऐसे कुछ कार्यक्रम हैं जो इस सुविधा को स्वचालित करते हैं, अपने आप को ऐसा करने से झुंझलाहट और संभावित कीड़े को दूर करते हैं, और पर्दे के पीछे झुंड का उपयोग करके बासी लॉक की समस्या से भी बचते हैं, (जो कि जोखिम है यदि आप सिर्फ स्पर्श का उपयोग कर रहे हैं) । मैंने उपयोग किया है lockrunऔर lckdoअतीत में है, लेकिन अब वहां flock(1) (उपयोग-लिनेक्स के नए संस्करणों में) जो बहुत अच्छा है। इसका उपयोग करना वास्तव में आसान है:

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job

2
मोरनी से लड्डू निकाले जा रहे हैं, अब वह झुंड (1) उपयोग में है। और यह पैकेज मूल रूप से लिनक्स सिस्टम में अनिवार्य है, इसलिए आपको इसकी उपस्थिति पर भरोसा करने में सक्षम होना चाहिए। उपयोग के लिए, नीचे देखें।
jldugger

हाँ, झुंड अब मेरा पसंदीदा विकल्प है। मैं अपने उत्तर को भी अपडेट करूंगा।
Womble

किसी flock -n file commandऔर के बीच अंतर पता है flock -n file -c command?
नन्ने

2
@ नया, मुझे निश्चित होने के लिए कोड की जांच करनी होगी, लेकिन मेरा शिक्षित अनुमान यह है कि -cनिर्दिष्ट कमांड को शेल के माध्यम से चलाया जाता है (मैनपेज के अनुसार), जबकि "नंगे" (गैर- -c) फॉर्म सिर्फ execदिए गए कमांड के अनुसार है । शेल के माध्यम से कुछ डालने से आप शेल-जैसी चीजें कर सकते हैं (जैसे कि कई कमांड को अलग-अलग चलाने ;या चलाने के लिए &&), लेकिन यदि आप बिना इनपुट के उपयोग कर रहे हैं, तो यह शेल विस्तार के हमलों को भी खोलता है।
Womble

1
यह (काल्पनिक) frequent_cron_jobआदेश का एक तर्क था जो यह दिखाने की कोशिश करता था कि इसे हर मिनट चलाया जा रहा है। मैंने इसे हटा दिया है क्योंकि इसमें कुछ भी उपयोगी नहीं था, और भ्रम पैदा हुआ (तुम्हारा, अगर कोई और नहीं है)।
Womble

28

शेल में सबसे अच्छा तरीका झुंड (1) का उपयोग करना है

(
  flock -x -w 5 99
  ## Do your stuff here
) 99>/path/to/my.lock

1
मैं fd पुनर्निर्देशन के एक मुश्किल उपयोग को बढ़ा नहीं सकता। यह अभी भी बहुत भयानक है।
Womble

1
मेरे लिए बैश या ZSH में पार्स नहीं करता, बीच में जगह को खत्म करने की जरूरत है 99और >इसलिए यह है99> /...
काइल ब्रान्ड

2
@ जेवियर: इसका मतलब यह नहीं है कि यह मुश्किल और रहस्यमय नहीं है, बस यह दस्तावेज , मुश्किल और रहस्यमय है।
वोमबल

1
यदि आप इसे चालू करते हैं या किसी भी तरह से मारे गए प्रक्रिया को प्राप्त करते हैं तो क्या होगा? क्या यह हमेशा के लिए बंद हो जाएगा?
एलेक्स आर

5
मैं समझता हूं कि यह संरचना एक विशेष ताला बनाती है, लेकिन मैं यांत्रिकी को यह नहीं समझता कि यह कैसे पूरा होता है। इस उत्तर में '99' का क्या कार्य है? किसी को भी यह समझाने की परवाह कृपया? धन्यवाद!
असिओम

22

दरअसल, flock -nइसका इस्तेमाल lckdo* के बजाय किया जा सकता है , इसलिए आप कर्नेल डेवलपर्स से कोड का उपयोग करेंगे।

Womble के उदाहरण पर बिल्डिंग , आप कुछ इस तरह लिखेंगे:

* * * * * flock -n /some/lockfile command_to_run_every_minute

Btw,, के सभी कोड को देख flock, lockrunहै, और lckdoबिल्कुल वही चीज़ करते, तो यह सिर्फ एक मामला है जिस की सबसे आसानी से आप के लिए उपलब्ध है।


2

आप लॉक फ़ाइल का उपयोग कर सकते हैं। स्क्रिप्ट शुरू होने पर इसे बनाएं और खत्म होने पर इसे हटा दें। स्क्रिप्ट, इसके मुख्य रूटीन को चलाने से पहले, यह देखना चाहिए कि क्या लॉक फ़ाइल मौजूद है और तदनुसार आगे बढ़ें।

लॉकफाइल्स का उपयोग इनस्क्रिप्ट और कई अन्य अनुप्रयोगों और यूनिक्स प्रणालियों में उपयोगिताओं द्वारा किया जाता है।


1
यह एकमात्र तरीका है जिसे मैंने इसे व्यक्तिगत रूप से कार्यान्वित करते हुए देखा है। मैं OSS परियोजना के लिए दर्पण के रूप में अनुचर के सुझाव के अनुसार उपयोग करता हूं
वॉरेन

2

यदि आप स्क्रिप्ट को पूर्ववर्ती रन के पूरा होने या न होने की प्रतीक्षा करना चाहते हैं, तो आपने निर्दिष्ट किया है। "मैं नहीं चाहता कि नौकरियां" एक-दूसरे के ऊपर "स्टैकिंग" शुरू करें, मुझे लगता है कि आप अनुमान लगा रहे हैं कि आप चाहते हैं कि स्क्रिप्ट पहले से ही चल रही हो, तो बाहर निकलें

इसलिए, यदि आप lckdo या समान पर निर्भर रहना चाहते हैं, तो आप यह कर सकते हैं:


PIDFILE=/tmp/`basename $0`.pid

if [ -f $PIDFILE ]; then
  if ps -p `cat $PIDFILE` > /dev/null 2>&1; then
      echo "$0 already running!"
      exit
  fi
fi
echo $$ > $PIDFILE

trap 'rm -f "$PIDFILE" >/dev/null 2>&1' EXIT HUP KILL INT QUIT TERM

# do the work


धन्यवाद आपका उदाहरण सहायक है - मैं चाहता हूं कि यदि पहले से ही चल रहा है तो स्क्रिप्ट बाहर निकल जाए। Ickdo उल्लेख करने के लिए धन्यवाद - यह चाल करने के लिए लगता है।
टॉम

एफडब्ल्यूआईडब्ल्यू: मुझे यह समाधान पसंद है क्योंकि इसे एक स्क्रिप्ट में शामिल किया जा सकता है, इसलिए लॉकिंग काम करता है, भले ही स्क्रिप्ट को कैसे लागू किया जाए।
डेविड जी

1

यह एक संकेत भी हो सकता है कि आप गलत काम कर रहे हैं। यदि आपकी नौकरियां उस निकट और उस बार भी चलती हैं, तो शायद आपको डी-क्रोनिंग पर विचार करना चाहिए और इसे एक डेमन-स्टाइल प्रोग्राम बनाना चाहिए।


3
मैं दिल से इससे असहमत हूं। यदि आपके पास कुछ है जिसे समय-समय पर चलाने की आवश्यकता है, तो इसे एक डेमन "अखरोट के लिए स्लेजहैमर" समाधान है। दुर्घटनाओं को रोकने के लिए लॉकफ़ाइल का उपयोग करना एक पूरी तरह से उचित समाधान है जिसका उपयोग करने में मुझे कभी समस्या नहीं हुई है।
Womble

@womble मैं सहमत हूँ; लेकिन मुझे स्लेजहामर्स के साथ पागल को मारना पसंद है! :-)
wzzrd

1

यदि आपके पिछले उदाहरण अभी भी चल रहे हैं तो आपके क्रोन डेमॉन को नौकरी नहीं देनी चाहिए। मैं एक क्रोन डेमॉन डेक्रॉन का डेवलपर हूं , और हम विशेष रूप से इसे रोकने की कोशिश करते हैं। मुझे नहीं पता कि विक्सी क्रोन या अन्य डेमॉन इसे कैसे संभालते हैं।


1

मैं रन-वन कमांड का उपयोग करने की सलाह दूंगा - तालों से निपटने की तुलना में बहुत सरल। डॉक्स से:

रन-वन एक रैपर स्क्रिप्ट है जो कि कुछ कमांड के एक से अधिक अद्वितीय उदाहरणों के एक अद्वितीय सेट के साथ चलती है। यह अक्सर क्रोनोजर के साथ उपयोगी होता है, जब आप एक बार में एक से अधिक कॉपी नहीं चलाना चाहते हैं।

रन- दिस-वन बिल्कुल रन-वन की तरह है, सिवाय इसके कि यह pgrep और मारने के लिए उपयोग करेगा और उपयोगकर्ता के स्वामित्व वाली किसी भी रनिंग प्रोसेस को खोजने और मारने के लिए टारगेट कमांड्स और तर्कों का मिलान करेगा। ध्यान दें कि जब तक सभी मिलान प्रक्रियाएँ समाप्त नहीं हो जाती हैं, तब तक यह मिलान प्रक्रिया को मारने की कोशिश करते हुए ब्लॉक हो जाएगा।

रन-वन-लगातार, बिल्कुल रन-वन की तरह संचालित होता है, सिवाय इसके कि यह "COMMAND [ARGS]" को किसी भी समय COMMAND (शून्य या गैर-शून्य) से बाहर निकालता है।

Keep-one- run रन-वन-लगातार के लिए एक उपनाम है।

रन-वन-जब तक सफलता बिल्कुल रन-वन-लगातार की तरह संचालित होती है सिवाय इसके कि यह "COMMAND [ARGS]" का जवाब देता है जब तक कि COMMAND सफलतापूर्वक बाहर नहीं निकलता (यानी, शून्य से बाहर निकलता है)।

रन-वन-जब तक विफलता रन-वन-लगातार की तरह संचालित होती है सिवाय इसके कि यह "COMMAND [ARGS]" का जवाब तब तक देता है जब तक COMMAND विफलता से बाहर नहीं निकलता (यानी, गैर-शून्य से बाहर निकलता है)।


1

अब यह प्रणाली समाप्त हो गई है, लिनक्स सिस्टम पर एक और शेड्यूलिंग तंत्र है:

systemd.timer

में /etc/systemd/system/myjob.serviceया ~/.config/systemd/user/myjob.service:

[Service]
ExecStart=/usr/local/bin/myjob

में /etc/systemd/system/myjob.timerया ~/.config/systemd/user/myjob.timer:

[Timer]
OnCalendar=minutely

[Install]
WantedBy=timers.target

यदि टाइमर अगले कार्यकलाप के दौरान सेवा इकाई पहले से ही सक्रिय है, तो सेवा का एक और उदाहरण शुरू नहीं किया जाएगा।

एक विकल्प, जो बूट पर एक बार काम शुरू करता है और प्रत्येक रन के समाप्त होने के एक मिनट बाद:

[Timer]
OnBootSec=1m
OnUnitInactiveSec=1m 

[Install]
WantedBy=timers.target

0

मैंने इस तरह के मुद्दे को हल करने के लिए एक जार बनाया है जैसे डुप्लिकेट क्रोन चल रहे हैं जावा या शेल क्रोन हो सकते हैं। Duplicates.CloseSession ("Demo.jar") में क्रोन नाम को पास करें, यह करंट को छोड़कर इस क्रॉन के लिए मौजूद पीएनजी को खोजेगा और मार देगा। मैंने इस सामान को करने के लिए विधि लागू की है। स्ट्रिंग का नाम = ManagementFactory.getRuntimeMXBean ()। GetName (); स्ट्रिंग pid = proname.split ("@") [0]; System.out.println ("करंट PID:" + pid);

            Process proc = Runtime.getRuntime().exec(new String[]{"bash","-c"," ps aux | grep "+cronname+" | awk '{print $2}' "});

            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String s = null;
            String killid="";

            while ((s = stdInput.readLine()) != null ) {                                        
                if(s.equals(pid)==false)
                {
                    killid=killid+s+" ";    
                }
            }

और फिर शेल स्ट्रिंग को फिर से शेल कमांड से मारें


मुझे नहीं लगता कि यह वास्तव में इस सवाल का जवाब है।
कसपर

0

@Philip रेनॉल्ड्स उत्तर 5s प्रतीक्षा समय के बाद कोड को निष्पादित करना शुरू कर देगा बिना लॉक किए बिना। झुंड के बाद काम नहीं कर रहा है मैं संशोधित @Philip रेनॉल्ड्स का जवाब

(
  flock -w 5 -x 99 || exit 1
  ## Do your stuff here
) 99>/path/to/my.lock

कोड को कभी भी एक साथ निष्पादित नहीं किया जाएगा। इसके बजाय 5 सेकंड प्रतीक्षा करने के बाद प्रक्रिया 1 के साथ बाहर निकल जाएगी अगर इसे तब तक ताला नहीं मिला।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.