यदि यह पहले से ही नहीं चल रहा है तो क्रोन जॉब चलाएं


136

तो मैं एक डेमॉन के लिए एक क्रोन जॉब सेट करने की कोशिश कर रहा हूं जो मैंने बनाया है। यदि डेमॉन त्रुटियां समाप्त हो जाती हैं और विफल हो जाती हैं, तो मैं चाहता हूं कि क्रोन नौकरी समय-समय पर इसे फिर से शुरू कर दे ... मुझे यकीन नहीं है कि यह कैसे संभव है, लेकिन मैंने कुछ क्रोन ट्यूटोरियल के माध्यम से पढ़ा और कुछ भी नहीं मिला जो मैं करूंगा मैं देख रहा हूँ ...

मेरा डेमॉन एक शेल स्क्रिप्ट से शुरू होता है, इसलिए मैं वास्तव में सिर्फ एक क्रोन जॉब चलाने का एक तरीका ढूंढ रहा हूं केवल अगर उस जॉब का पिछला रन अभी भी नहीं चल रहा है।

मुझे यह पोस्ट मिली , जो मुझे लॉक फ़ाइलों का उपयोग करने के लिए जो करने की कोशिश कर रहा है, उसके लिए एक समाधान प्रदान किया गया था, न कि मुझे यकीन नहीं है कि यह करने का एक बेहतर तरीका है ...

आपकी सहायता के लिए धन्यवाद।

जवाबों:


120

मैं एक प्रिंट स्पूलर प्रोग्राम के लिए ऐसा करता हूं जो मैंने लिखा था, यह सिर्फ एक शेल स्क्रिप्ट है:

#!/bin/sh
if ps -ef | grep -v grep | grep doctype.php ; then
        exit 0
else
        /home/user/bin/doctype.php >> /home/user/bin/spooler.log &
        #mailing program
        /home/user/bin/simplemail.php "Print spooler was not running...  Restarted." 
        exit 0
fi

यह हर दो मिनट पर चलता है और काफी प्रभावी है। मेरे पास यह मुझे विशेष जानकारी के साथ ईमेल करता है यदि किसी कारण से प्रक्रिया नहीं चल रही है।


4
एक बहुत ही सुरक्षित समाधान नहीं है, हालांकि, क्या होगा अगर अन्य प्रक्रिया है जो आपके द्वारा grep में की गई खोज से मेल खाती है? rsanden का जवाब उस तरह की समस्या को रोकता है, जो पिडफाइल का उपयोग करता है।
एलियास डोर्नेलस

12
इस पहिये का आविष्कार पहले ही कहीं और किया गया था :) Eg, serverfault.com/a/82863/108394
फिलिप कोर्रेया

5
इसके बजाय grep -v grep | grep doctype.phpआप कर सकते हैं grep [d]octype.php
एलेक्सटी

ध्यान दें कि &स्क्रिप्ट चलाने वाले क्रोन की कोई आवश्यकता नहीं है ।
13

124

का उपयोग करें flock। यह नया है। यह बेहतर है।

अब आपको कोड खुद लिखने की जरूरत नहीं है। यहां और अधिक कारण देखें : https://serverfault.com/a/82863

/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script

1
एक बहुत ही आसान उपाय
MFB

4
सबसे अच्छा समाधान, मैं वास्तव में लंबे समय से इसका उपयोग कर रहा हूं।
सोगर

1
मैंने यहां एक अच्छा क्रोन टेम्प्लेट भी तैयार किया: gist.github.com/jesslilly/315132a59f749c11b7c6
Jess

3
setlock, s6-setlock, chpst, और runlockउनके गैर अवरुद्ध मोड में विकल्प है कि बस लिनक्स की तुलना में अधिक पर उपलब्ध हैं। unix.stackexchange.com/a/475580/5132
JdeBP

3
मुझे लगता है कि यह स्वीकृत उत्तर होना चाहिए। बहुत आसन!
कोडमेकिन

62

जैसा कि दूसरों ने कहा है, पीआईडी ​​फाइल लिखना और जांचना एक अच्छा उपाय है। यहाँ मेरा बैश कार्यान्वयन है:

#!/bin/bash

mkdir -p "$HOME/tmp"
PIDFILE="$HOME/tmp/myprogram.pid"

if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= |
                           grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then
  echo "Already running."
  exit 99
fi

/path/to/myprogram > $HOME/tmp/myprogram.log &

echo $! > "${PIDFILE}"
chmod 644 "${PIDFILE}"

3
+1 एक पीडिफ़ाइल का उपयोग करना संभवतः उसी नाम के साथ चल रहे प्रोग्राम के लिए टकराने से अधिक सुरक्षित है।
एलियास डोर्नेलस

/ path / to / myprogram &> $ HOME / tmp / myprogram.log & ?????? क्या आप शायद मतलब / पथ / / से / myprogram >> $ HOME / tmp / myprogram.log &
matteo

1
स्क्रिप्ट खत्म होने पर फ़ाइल को हटाया नहीं जाना चाहिए? या मैं कुछ बहुत स्पष्ट याद कर रहा हूँ?
हमजाहरुक

1
@matteo: हाँ, तुम सही हो। मैंने अपने नोट्स में वर्षों पहले यह तय कर लिया था लेकिन इसे यहाँ अपडेट करना भूल गया। इससे भी बदतर, मैंने इसे आपकी टिप्पणी में भी याद किया, केवल " >" बनाम " >>" पर ध्यान दिया। उसके लिए माफ़ करना।
rsanden

5
@ Hamzahfrq: यहां बताया गया है कि यह कैसे काम करता है: स्क्रिप्ट पहले यह देखने के लिए जांच करती है कि क्या पीआईडी ​​फ़ाइल मौजूद है (" [ -e "${PIDFILE}" ]"। यदि ऐसा नहीं होता है, तो यह पृष्ठभूमि में कार्यक्रम शुरू करेगा, इसकी पीआईडी ​​को एक फ़ाइल (" echo $! > "${PIDFILE}""), और) पर लिखें। बाहर निकलें। यदि इसके बजाय पीआईडी ​​फ़ाइल मौजूद है, तो स्क्रिप्ट आपकी खुद की प्रक्रियाओं (" ps -u $(whoami) -opid=") की जांच करेगी और देखें कि क्या आप उसी पीआईडी ​​(" grep -P "^\s*$(cat ${PIDFILE})$"") के साथ चल रहे हैं । यदि आप नहीं हैं, तो यह शुरू हो जाएगा। कार्यक्रम पहले की तरह, नई PID के साथ PID फ़ाइल को अधिलेखित करें, और बाहर निकलें। मुझे स्क्रिप्ट को संशोधित करने का कोई कारण नहीं
दिखता है

35

यह आश्चर्य की बात है कि रन-वन के बारे में किसी ने उल्लेख नहीं किया है । मैंने इसके साथ अपनी समस्या हल कर ली है।

 apt-get install run-one

फिर run-oneअपनी क्रॉस्टैब स्क्रिप्ट से पहले जोड़ें

*/20 * * * * * run-one python /script/to/run/awesome.py

इस Askubuntu SE उत्तर की जाँच करें । आप एक विस्तृत जानकारी के लिए लिंक भी पा सकते हैं।


22

क्रोन के माध्यम से करने की कोशिश मत करो। क्या क्रोन ने कोई स्क्रिप्ट चलाई है या नहीं, और उसके बाद स्क्रिप्ट तय करें कि क्या प्रोग्राम चल रहा है और यदि आवश्यक हो तो इसे शुरू करें (ध्यान दें कि आप ऐसा करने के लिए रूबी या पायथन या अपनी पसंदीदा स्क्रिप्टिंग भाषा का उपयोग कर सकते हैं)


5
क्लासिक तरीका एक पीआईडी ​​फ़ाइल पढ़ना है जो सेवा शुरू होने पर बनाता है, यह जांचें कि क्या उस पीआईडी ​​के साथ प्रक्रिया अभी भी चल रही है, और यदि नहीं तो पुनरारंभ करें।
तवान्फोसन

9

आप इसे सीधे अपने कॉन्ट्राब में वन-लाइनर के रूप में भी कर सकते हैं:

* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>

5
बहुत सुरक्षित नहीं है, क्या होगा अगर अन्य कमांड हैं जो grep की खोज से मेल खाते हैं?
एलियास डोर्नेलस

1
इसे * * * * * [ ps -ef|grep [c]ommand-eq 0] && <कमांड> के रूप में भी लिखा जा सकता है, जहां कोष्ठक में आपकी कमांड के पहले अक्षर को लपेटकर इसे grep परिणामों से बाहर रखा गया है।
जिम क्लॉज

मुझे निम्नलिखित वाक्यविन्यास का उपयोग करना था:[ "$(ps -ef|grep [c]ommand|wc -l)" -eq 0 ] && <command>
thameera

1
यह गूढ़ है। [ $(grep something | wc -l) -eq 0 ]लिखने के लिए एक बहुत ही गोल चक्कर रास्ता है ! grep -q something। तो आप बस चाहते हैंps -ef | grep '[c]ommand' || command
ट्रिपल

(इसके अलावा, एक तरफ के रूप में, यदि आप वास्तव में मिलान लाइनों की संख्या को गिनना चाहते हैं, तो grep -c।)
ट्रिपल

7

जिस तरह से मैं कर रहा हूँ जब मैं php स्क्रिप्ट चला रहा हूँ:

Crontab:

* * * * * php /path/to/php/script.php &

Php कोड:

<?php
if (shell_exec('ps aux | grep ' . __FILE__ . ' | wc  -l') > 1) {
    exit('already running...');
}
// do stuff

यह कमांड वर्तमान php फ़ाइलनाम के लिए सिस्टम प्रोसेस सूची में खोज कर रहा है यदि यह मौजूद है तो लाइन काउंटर (wc -l) अधिक होगा, क्योंकि खोज कमांड में ही फाइलनेम होता है

इसलिए यदि आप php crons चलाते हैं तो उपरोक्त कोड को अपने php कोड के प्रारंभ में जोड़ दें और यह केवल एक बार चलेगा।


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

5

अर्लज़ उत्तर के लिए अनुवर्ती के रूप में, आपको एक आवरण स्क्रिप्ट की आवश्यकता होती है जो $ PID.running फ़ाइल बनाता है जब यह शुरू होता है, और जब यह समाप्त होता है तो हटा दें। आवरण स्क्रिप्ट वह स्क्रिप्ट कहती है जिसे आप चलाना चाहते हैं। आवरण स्क्रिप्ट आवश्यक होने पर लक्ष्य स्क्रिप्ट विफल हो जाती है या त्रुटियां हो जाती हैं, तो पिड फ़ाइल डिलीट हो जाती है।


ओह कूल ... मैंने कभी रैपर का उपयोग करने के बारे में नहीं सोचा था ... मैं इसे लॉक फ़ाइलों का उपयोग करने का एक तरीका नहीं समझ सका क्योंकि मैं गारंटी नहीं दे सकता था कि डेमॉन को गलत तरीके से हटाए जाने पर फ़ाइल को हटा दिया जाएगा ... ए रैपर पूरी तरह से काम करेगा, मैं jjclarkson के समाधान को एक शॉट देने जा रहा हूं, लेकिन मैं यह करूंगा अगर यह काम नहीं करता है ...
लॉरेनवीस


3

मैं मौद्रिक जैसे मौजूदा उपकरण का उपयोग करने की सलाह दूंगा, यह प्रक्रियाओं की निगरानी और फिर से शुरू करेगा। अधिक जानकारी यहाँ उपलब्ध है । यह अधिकांश वितरण में आसानी से उपलब्ध होना चाहिए।


इसके अलावा प्रत्येक उत्तर सतह के प्रश्न का उत्तर देता है "मेरा क्रोन काम कैसे सुनिश्चित कर सकता है कि यह केवल एक उदाहरण चलाता है?" जब असली सवाल यह है कि "मैं अपनी प्रक्रिया को पुनरारंभ के चेहरे पर कैसे चला सकता हूं?", और सही उत्तर वास्तव में क्रोन का उपयोग नहीं करना है, बल्कि एक प्रक्रिया पर्यवेक्षक जैसे कि मोनिट। अन्य विकल्पों में शामिल हैं RUNIT , S6 या, यदि आपके वितरण के पहले से ही systemd का उपयोग करता है, बस प्रक्रिया के लिए एक systemd सेवा बनाने की जरूरत को जीवित रखा जा सकता है कि।
क्लॅक

3

यह मुझे कभी असफल नहीं हुआ:

one.sh :

LFILE=/tmp/one-`echo "$@" | md5sum | cut -d\  -f1`.pid
if [ -e ${LFILE} ] && kill -0 `cat ${LFILE}`; then
   exit
fi

trap "rm -f ${LFILE}; exit" INT TERM EXIT
echo $$ > ${LFILE}

$@

rm -f ${LFILE}

क्रॉन जॉब :

* * * * * /path/to/one.sh <command>

3
# one instance only (works unless your cmd has 'grep' in it)
ALREADY_RUNNING_EXIT_STATUS=0
bn=`basename $0`
proc=`ps -ef | grep -v grep | grep "$bn" | grep -v " $$ "`
[ $? -eq 0 ] && {
    pid=`echo $proc | awk '{print $2}'`
    echo "$bn already running with pid $pid"
    exit $ALREADY_RUNNING_EXIT_STATUS
}

अद्यतन .. बेहतर तरीका झुंड का उपयोग कर:

/usr/bin/flock -n /tmp/your-app.lock /path/your-app args 

1

मैं rsanden के उत्तर में सुधार के रूप में निम्नलिखित सुझाव दूंगा (मैं एक टिप्पणी के रूप में पोस्ट करूंगा, लेकिन पर्याप्त प्रतिष्ठा नहीं है ...):

#!/usr/bin/env bash

PIDFILE="$HOME/tmp/myprogram.pid"

if [ -e "${PIDFILE}" ] && (ps -p $(cat ${PIDFILE}) > /dev/null); then
  echo "Already running."
  exit 99
fi

/path/to/myprogram

यह संभव झूठे मैचों (और पकने के ओवरहेड) से बचा जाता है, और यह आउटपुट को दबा देता है और केवल पीएस के बाहर निकलने की स्थिति पर निर्भर करता है।


1
आपकी psकमांड सिस्टम के अन्य उपयोगकर्ताओं के लिए PID से मेल खाएगी, न कि केवल आपकी ही। कमांड में " -u" जोड़ने psसे बाहर निकलने की स्थिति के काम करने का तरीका बदल जाता है।
रैंडन

1

सरल कस्टम php प्राप्त करने के लिए पर्याप्त है। शेल स्क्रिप्ट के साथ भ्रमित करने की आवश्यकता नहीं है।

मान लें कि आप php /home/mypath/example.php चलाना चाहते हैं यदि नहीं चल रहे हैं

फिर उसी काम को करने के लिए कस्टम php स्क्रिप्ट का उपयोग करें।

निम्नलिखित /home/mypath/forever.php बनाएं

<?php
    $cmd = $argv[1];
    $grep = "ps -ef | grep '".$cmd."'";
    exec($grep,$out);
    if(count($out)<5){
        $cmd .= ' > /dev/null 2>/dev/null &';
        exec($cmd,$out);
        print_r($out);
    }
?>

फिर अपने क्रोन में निम्नलिखित जोड़ें

* * * * * php /home/mypath/forever.php 'php /home/mypath/example.php'

0

अगर आप उस मार्ग से जाने वाले हैं, तो grep के माध्यम से पीएस पाइप के बजाय pgrep (यदि उपलब्ध हो) का उपयोग करने पर विचार करें। हालाँकि, व्यक्तिगत रूप से, मुझे फ़ॉर्म की स्क्रिप्ट से बहुत अधिक लाभ मिला है

while(1){
  call script_that_must_run
  sleep 5
}

हालांकि इस असफल और कर सकते हैं क्रॉन नौकरियों हैं अक्सर आवश्यक सामान के लिए सबसे अच्छा तरीका है। बस एक और विकल्प।


2
यह सिर्फ बार-बार डेमॉन शुरू करेगा और ऊपर बताई गई समस्या को हल नहीं करेगा।
कोवेकर

0

डॉक्स: https://www.timkay.com/solo/

सोलो एक बहुत ही सरल स्क्रिप्ट (10 लाइनें) है जो एक प्रोग्राम को एक बार में एक से अधिक कॉपी चलाने से रोकती है। यह सुनिश्चित करने के लिए क्रोन के साथ उपयोगी है कि एक नौकरी खत्म होने से पहले नहीं चलती है।

उदाहरण

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