यदि मैं मर जाता है तो किसी प्रक्रिया को पुनः आरंभ करने के लिए मैं एक bash स्क्रिप्ट कैसे लिख सकता हूँ?


226

मेरे पास एक पायथन स्क्रिप्ट है जो एक कतार की जाँच करेगा और प्रत्येक आइटम पर एक क्रिया कर रहा होगा:

# checkqueue.py
while True:
  check_queue()
  do_something()

मैं एक बैश स्क्रिप्ट कैसे लिखूं जो यह जांच करेगी कि क्या चल रहा है, और यदि नहीं, तो इसे शुरू करें। मोटे तौर पर निम्नलिखित छद्म कोड (या शायद यह कुछ ऐसा करना चाहिए ps | grep?):

# keepalivescript.sh
if processidfile exists:
  if processid is running:
     exit, all ok

run checkqueue.py
write processid to processidfile

मैं उसे एक कोंट्राब से बुलाऊंगा:

# crontab
*/5 * * * * /path/to/keepalivescript.sh

4
बस इसे 2017 के लिए जोड़ना है। पर्यवेक्षक का उपयोग करें। crontab इस तरह के कार्य करने के लिए नहीं है। एक बैश स्क्रिप्ट वास्तविक त्रुटि को छोड़ने पर भयानक है। stackoverflow.com/questions/9301494/…
मटूटूट

अन्य गैर-सिस्टम समाधानों के बजाय इनटैब और रेस्पॉन का उपयोग कैसे करें? देखें superuser.com/a/507835/116705
लार्स Nordin

जवाबों:


635

PID-files, crons, या ऐसी अन्य चीज़ों से बचें जो उन प्रक्रियाओं का मूल्यांकन करने की कोशिश करती हैं जो उनके बच्चे नहीं हैं।

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

इसके बजाय आपको उस प्रक्रिया की आवश्यकता है जो प्रक्रिया को आपके माता-पिता बनने की प्रक्रिया की निगरानी करती है। इसका क्या मतलब है? इसका मतलब केवल यह है कि आपकी प्रक्रिया शुरू होने वाली प्रक्रिया समाप्त होने के लिए मज़बूती से इंतजार कर सकती है। बैश में, यह बिल्कुल तुच्छ है।

until myserver; do
    echo "Server 'myserver' crashed with exit code $?.  Respawning.." >&2
    sleep 1
done

बैश कोड का उपरोक्त टुकड़ा लूप myserverमें चलता है until। पहली पंक्ति शुरू होती है myserverऔर इसके खत्म होने का इंतजार करती है। जब यह समाप्त हो जाता है, तो untilइसकी निकास स्थिति की जांच करता है। यदि निकास की स्थिति है 0, तो इसका मतलब है कि यह इनायत से समाप्त हो गया है (जिसका अर्थ है कि आपने इसे किसी तरह बंद करने के लिए कहा था, और इसने सफलतापूर्वक ऐसा किया)। उस स्थिति में हम इसे पुनः आरंभ नहीं करना चाहते हैं (हमने इसे बंद करने के लिए कहा है!)। यदि बाहर निकलने की स्थिति नहीं है 0 , untilतो लूप बॉडी चलाएगा, जो STDERR पर एक त्रुटि संदेश देता है और 1 सेकंड के बाद लूप (पंक्ति 1 पर वापस) को पुनरारंभ करता है ।

हम एक सेकंड इंतजार क्यों करते हैं? क्योंकि यदि स्टार्टअप अनुक्रम के साथ कुछ गलत है myserverऔर यह तुरंत क्रैश हो जाता है, तो आपके हाथों पर लगातार पुनरारंभ और दुर्घटनाग्रस्त होने का एक बहुत ही गहन लूप होगा। sleep 1कि से तनाव दूर ले जाता है।

अब आपको बस इतना करना है कि इस बैश स्क्रिप्ट को शुरू करें (एसिंक्रोनस रूप से, शायद), और यह निगरानी करेगा और इसे myserverआवश्यक रूप से पुनरारंभ करेगा । यदि आप बूट पर मॉनिटर शुरू करना चाहते हैं (सर्वर को "जीवित" रिबूट बनाते हैं), तो आप इसे एक @rebootनियम के साथ अपने उपयोगकर्ता के क्रोन (1) में शेड्यूल कर सकते हैं । इसके साथ अपने क्रोन नियम खोलें crontab:

crontab -e

फिर अपनी मॉनिटर स्क्रिप्ट शुरू करने के लिए एक नियम जोड़ें:

@reboot /usr/local/bin/myservermonitor

वैकल्पिक रूप से, Inittab (5) और / etc / inittab को देखें। आप myserverएक निश्चित इनिट स्तर पर शुरू करने के लिए एक लाइन जोड़ सकते हैं और स्वचालित रूप से रिस्पांड हो सकते हैं।


संपादित करें।

मुझे पीआईडी ​​फ़ाइलों का उपयोग करने के बारे में कुछ जानकारी जोड़ने दें । जबकि वे बहुत लोकप्रिय हैं; वे भी बहुत त्रुटिपूर्ण हैं और कोई कारण नहीं है कि आप इसे सही तरीके से नहीं करेंगे।

इस पर विचार करो:

  1. पीआईडी ​​रीसाइक्लिंग (गलत प्रक्रिया को मारना):

    • /etc/init.d/foo start: शुरू करें foo, fooपीआईडी ​​को लिखें/var/run/foo.pid
    • थोड़ी देर बाद: fooकिसी तरह मर जाता है।
    • थोड़ी देर बाद: कोई भी यादृच्छिक प्रक्रिया जो शुरू होती है (इसे कॉल करें bar) एक यादृच्छिक पीआईडी ​​लेती है, कल्पना करें कि यह fooपुरानी पीआईडी ​​है।
    • आप देखते हैं foo: /etc/init.d/foo/restartपढ़ता है /var/run/foo.pid, यह देखने के लिए जाँच करता है कि क्या यह अभी भी जीवित है, पाता है bar, यह सोचता है foo, इसे मारता है, एक नई शुरुआत करता है foo
  2. पीआईडी ​​फाइलें बासी हो जाती हैं। आपको अधिक जटिल (या मुझे कहना चाहिए, गैर-तुच्छ) तर्क की जांच करने के लिए कि क्या पीआईडी ​​फ़ाइल बासी है, और ऐसा कोई भी तर्क फिर से कमजोर है 1.

  3. क्या होगा यदि आपके पास लिखने की पहुंच नहीं है या केवल पढ़ने के लिए वातावरण में हैं?

  4. यह व्यर्थ है ओवरकम्प्लिकेशन; देखें कि ऊपर मेरा उदाहरण कितना सरल है। कोई जटिल करने की जरूरत नहीं है, बिल्कुल।

यह भी देखें: क्या 'सही' करते समय पीआईडी-फाइलें अभी भी त्रुटिपूर्ण हैं?

वैसे; PID फ़ाइलों से भी बदतर पार्सिंग है ps! ऐसा कभी मत करो।

  1. psबहुत ही अस्थिर है। जब आप इसे लगभग हर यूनिक्स प्रणाली पर पाते हैं; यदि आप गैर-मानक आउटपुट चाहते हैं तो इसके तर्क बहुत भिन्न हैं। और मानक उत्पादन केवल मानव उपभोग के लिए है, स्क्रिप्टेड पार्सिंग के लिए नहीं!
  2. पार्स psकरने से झूठे सकारात्मक का एक बहुत होता है। ps aux | grep PIDउदाहरण लें , और अब कल्पना करें कि कोई व्यक्ति एक संख्या के साथ एक प्रक्रिया शुरू कर सकता है, जो तर्क के रूप में होता है कि पीआईडी ​​के समान ही आप अपने डेमन के साथ घूरते थे! एक एक्स सत्र शुरू करने वाले दो लोगों की कल्पना करें और आप एक्स को मारने के लिए आपका स्वागत कर रहे हैं। यह हर तरह का बुरा है।

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


1
@Chas। मालिक: मुझे नहीं लगता कि यह आवश्यक है। यह सिर्फ अच्छे कारण के लिए कार्यान्वयन को जटिल करेगा। सादगी हमेशा अधिक महत्वपूर्ण होती है; और यदि यह अक्सर पुनः आरंभ होता है, तो नींद आपके सिस्टम संसाधनों पर कोई बुरा प्रभाव डालने से बचाएगी। पहले से ही एक संदेश है।
लुनानाथ

2
@orschiro जब प्रोग्राम व्यवहार करता है तो कोई संसाधन खपत नहीं होती है। यदि यह तुरंत लॉन्च पर मौजूद है, तो लगातार, एक नींद 1 के साथ संसाधन की खपत अभी भी पूरी तरह से नगण्य है।
लवनाथ

7
विश्वास कर सकता हूं कि मैं सिर्फ इस जवाब को देख रहा हूं । बहुत बहुत धन्यवाद!
getWeberForStackExchange

2
@ TomášZato आप प्रक्रिया के निकास कोड का परीक्षण किए बिना उपरोक्त लूप कर सकते हैं while true; do myprocess; doneलेकिन ध्यान दें कि अब प्रक्रिया को रोकने का कोई तरीका नहीं है।
लुननाथ

2
@ सर्गेपी.काज़ुरे, माता-पिता को बच्चे को मारने के लिए बलपूर्वक बाहर निकलने के लिए मजबूर करने का एकमात्र तरीका है कि बच्चे को नौकरी में बदल दें और उसे संकेत दें:trap 'kill $(jobs -p)' EXIT; until myserver & wait; do sleep 1; done
लूनाथ

33

Monit ( http://mmonit.com/monit/ ) पर एक नज़र डालें । यह आपकी स्क्रिप्ट के स्टार्ट, स्टॉप और रिस्टार्ट को हैंडल करता है और यदि आवश्यक हो तो हेल्थ चेक प्लस रीस्टार्ट भी कर सकता है।

या एक साधारण स्क्रिप्ट करें:

while true
do
/your/script
sleep 1
done

4
मोनिट वही है जो आप ढूंढ रहे हैं।
सरके

4
"जबकि 1" काम नहीं करता है। आपको "जबकि [1]" या "जबकि सच है" या "जबकि:" चाहिए। देखें unix.stackexchange.com/questions/367108/what-does-ORE-mean
Curtis

8

इसे करने का सबसे आसान तरीका फ़ाइल पर झुंड का उपयोग करना है। पायथन लिपि में आप क्या करेंगे

lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0): 
   sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()

शेल में आप वास्तव में परीक्षण कर सकते हैं यदि यह चल रहा है:

if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then 
   echo 'it's not running'
   restart.
else
   echo -n 'it's already running with PID '
   cat /tmp/script.lock
fi

लेकिन निश्चित रूप से आपको परीक्षण करने की आवश्यकता नहीं है, क्योंकि अगर यह पहले से ही चल रहा है और आप इसे पुनः आरंभ करते हैं, तो यह आपके साथ बाहर निकल जाएगा 'other instance already running'

जब प्रक्रिया मर जाती है, तो सभी फ़ाइल विवरणक बंद हो जाते हैं और सभी ताले स्वचालित रूप से हटा दिए जाते हैं।


यह बश लिपि को हटाकर गर्भधारण को थोड़ा सरल बना सकता है। अजगर लिपि के दुर्घटनाग्रस्त होने पर क्या होता है? फ़ाइल अनलॉक है?
टॉम

1
फ़ाइल लॉक, जैसे ही आवेदन बंद हो जाता है, या तो हत्या करके, स्वाभाविक रूप से या दुर्घटनाग्रस्त हो जाता है।
क्रिश्चियन विट्स

@Tom ... थोड़ा और सटीक होने के लिए - जैसे ही फाइल बंद होती है, वैसे ही लॉक सक्रिय नहीं रहता। यदि पायथन स्क्रिप्ट कभी भी इरादे से फ़ाइल हैंडल को बंद नहीं करती है, और यह सुनिश्चित करती है कि यह फ़ाइल ऑब्जेक्ट के माध्यम से कचरा एकत्र किए जाने के माध्यम से स्वचालित रूप से बंद नहीं होता है, तो इसका मतलब है कि स्क्रिप्ट से बाहर निकलने का मतलब है / मारा गया था। यह रिबूट और इस तरह के लिए भी काम करता है।
चार्ल्स डफी

1
उपयोग करने के बहुत बेहतर तरीके हैं flock... वास्तव में, मैन पेज स्पष्ट रूप से दर्शाता है कि कैसे! exec {lock_fd}>/tmp/script.lock; flock -x "$lock_fd"आपके पाइथन के बराबर बैश है, और आयोजित लॉक को छोड़ देता है (इसलिए यदि आप किसी प्रक्रिया को निष्पादित करते हैं, तो लॉक उस प्रक्रिया से बाहर रहने तक रहेगा)।
चार्ल्स डफी

मैंने आपको नीचा दिखाया क्योंकि आपका कोड गलत है। उपयोग करना flockसही तरीका है, लेकिन आपकी स्क्रिप्ट गलत हैं। एकमात्र आदेश जिसे आपको flock -n /tmp/script.lock -c '/path/to/my/script.py'
क्रॉस्टैब

6

आपको मॉनेट का उपयोग करना चाहिए, एक मानक यूनिक्स उपकरण जो सिस्टम पर विभिन्न चीजों की निगरानी कर सकता है और तदनुसार प्रतिक्रिया कर सकता है।

डॉक्स से: http://mmonit.com/monit/documentation/monit.html#pid_testing

चेक प्रक्रिया pquefile /var/run/checkqueue.pid के साथ checkqueue.py
       अगर बदल गया तो "checkqueue_restart.sh" निष्पादित करें

जब यह पुनरारंभ होता है तो आप आपको ईमेल भेजने के लिए भी मोनिट कॉन्फ़िगर कर सकते हैं।


2
मोनेट एक महान उपकरण है, लेकिन यह पोसिक्स या एसयूएसवी में निर्दिष्ट होने के औपचारिक अर्थ में मानक नहीं है
चार्ल्स डफी

5
if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
    restart_process
    # Write PIDFILE
    echo $! >$PIDFILE
fi

शांत, कि मेरे छद्म कोड के कुछ बहुत अच्छी तरह से fleshing है। दो qns: 1) मैं PIDFILE कैसे उत्पन्न करूं? 2) psgrep क्या है? यह ubuntu सर्वर पर नहीं है।
टॉम

ps grep सिर्फ एक छोटा सा ऐप है जो जैसा करता है वैसा ही करता है ps ax|grep ...। आप बस इसे स्थापित कर सकते हैं या उसके लिए एक फ़ंक्शन लिख सकते हैं: फ़ंक्शन psgrep () {ps ax | grep -v grep | grep -q "$ 1"}
soulmerge

बस ध्यान दिया कि मैंने आपके पहले प्रश्न का उत्तर नहीं दिया था।
सोलमरेज

7
वास्तव में व्यस्त सर्वर पर यह संभव है कि जांच से पहले पीआईडी ​​आपको पुनर्नवीनीकरण कर देगा।
वार्टेक

2

मुझे यकीन नहीं है कि ऑपरेटिंग सिस्टम में यह कितना पोर्टेबल है, लेकिन आप जांच सकते हैं कि क्या आपके सिस्टम में 'रन-वन' कमांड है, अर्थात "मैन रन-वन"। विशेष रूप से, इस आदेश के सेट में 'रन-वन-लगातार' शामिल है, जो ठीक उसी तरह लगता है जिसकी आवश्यकता है।

मैन पेज से:

रन-वन-लगातार COMMAND [ARGS]

नोट: जाहिर है कि यह आपकी स्क्रिप्ट के भीतर से बुलाया जा सकता है, लेकिन यह भी एक स्क्रिप्ट होने की आवश्यकता को हटा देता है।


क्या यह स्वीकृत उत्तर पर कोई लाभ देता है?
ट्रिपलए

1
हां, मुझे लगता है कि एक शेल स्क्रिप्ट लिखने की तुलना में बिल्ट-इन कमांड का उपयोग करना बेहतर है, वही काम करता है जिसे सिस्टम कोडबेस के हिस्से के रूप में बनाए रखना होगा। भले ही कार्यक्षमता शेल स्क्रिप्ट के भाग के रूप में आवश्यक हो, उपरोक्त कमांड का उपयोग भी किया जा सकता है, इसलिए यह शेल स्क्रिप्टिंग प्रश्न के लिए प्रासंगिक है।
डैनियल ब्रैडली

यह "में निर्मित" नहीं है; यदि यह कुछ डिस्ट्रो पर डिफ़ॉल्ट रूप से स्थापित है, तो आपके उत्तर को संभवतः डिस्ट्रो निर्दिष्ट करना चाहिए (और आदर्श रूप से एक पॉइंटर को शामिल करना चाहिए जहां इसे डाउनलोड करने के लिए यदि आपका उनमें से एक नहीं है)।
ट्रिपलए

ऐसा लगता है कि यह एक उबंटू उपयोगिता है; लेकिन यह उबंटू पर भी वैकल्पिक है। manpages.ubuntu.com/manpages/bionic/man1/run-one.1.html
tripleee

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

1

मैंने कई सर्वरों पर बड़ी सफलता के साथ निम्नलिखित स्क्रिप्ट का उपयोग किया है:

pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
echo $INSTALLATION found at PID $pid 
while [ -e /proc/$pid ]; do sleep 0.1; done

टिप्पणियाँ:

  • यह एक जावा प्रक्रिया की तलाश में है, इसलिए मैं jps का उपयोग कर सकता हूं, यह ps की तुलना में वितरण में बहुत अधिक सुसंगत है
  • $INSTALLATION इसमें पर्याप्त पथ प्रक्रिया है जिसमें यह पूरी तरह से अस्पष्ट है
  • प्रक्रिया के मरने की प्रतीक्षा करते हुए नींद का उपयोग करें, संसाधनों से बचने से बचें :)

यह स्क्रिप्ट वास्तव में टॉमकैट के एक रनिंग इंस्टेंस को बंद करने के लिए उपयोग की जाती है, जिसे मैं कमांड लाइन पर बंद करना (और प्रतीक्षा करना) चाहता हूं, इसलिए इसे चाइल्ड प्रोसेस के रूप में लॉन्च करना मेरे लिए एक विकल्प नहीं है।


1
grep | awkअभी भी एक एंटीपैटर्न है - आप awk "/$INSTALLATION/ { print \$1 }"बेकार grepस्क्रिप्ट को अवाक स्क्रिप्ट में बदलना चाहते हैं , जो कि नियमित अभिव्यक्ति द्वारा लाइनों को बहुत अच्छी तरह से पा सकते हैं, बहुत-बहुत धन्यवाद।
त्रिवेणी 12:00

0

मैं अपने npm प्रक्रिया के लिए इसका उपयोग करता हूं

#!/bin/bash
for (( ; ; ))
do
date +"%T"
echo Start Process
cd /toFolder
sudo process
date +"%T"
echo Crash
sleep 1
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.