क्या स्क्रिप्ट को जीवित रखने के लिए "सही है" का उपयोग करना एक अच्छा विचार है?


19

मैं बस एक अलग दुनिया से यूनिक्स में कूद रहा हूं, और जानना चाहता हूं कि क्या

while true
do
  /someperlscript.pl
done

पर्ल स्क्रिप्ट में आंतरिक रूप से एक फ़ोल्डर / फ़ाइल द्रष्टा होता है जो लक्ष्य स्थान में फ़ाइलों को बदलने पर निष्पादित होता है।

क्या यह ( while true) एक अच्छा विचार है? यदि नहीं, तो एक पसंदीदा मजबूत दृष्टिकोण क्या है?

TIA

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

लेकिन - यदि प्रक्रिया किसी कारण से विफल हो जाती है, तो हम चाहते हैं कि यह ऊपर और चल रहा है और अगली फ़ाइल से निपटें, क्योंकि अगली फ़ाइल पिछले एक से पूरी तरह से असंबंधित है जो त्रुटि का कारण हो सकती है।

आमतौर पर मैं किसी न किसी तरह से सभी को पकड़ लेता था और इसके चारों ओर पूरे कोड को लपेट देता था ताकि यह दुर्घटनाग्रस्त हो जाए। लेकिन पर्ल के लिए निश्चित नहीं था।

मैंने जो कुछ भी समझा है, उसमें से पर्यवेक्षक की तरह कुछ का उपयोग करना इसके लिए एक अच्छा तरीका है।


9
क्या यह लिनक्स या यूनिक्स है? यदि यह लिनक्स है तो आप inotifyएपीआई की जांच कर सकते हैं ताकि आप अपने लक्ष्य निर्देशिका में बदलने के लिए फाइलों के इंतजार में व्यस्त लूप से बच सकें।
रोज़ा


यदि आप जानते हैं कि फ़ाइल पीआई छोड़ने से पहले अच्छी है, तो आप बस md5 या sha1 की तरह एक चेकसम चला सकते हैं और अपनी फ़ाइल के साथ भेज सकते हैं। तब रिसीवर को पता चल जाएगा कि क्या इसे प्रोसेस करने की कोशिश करने से पहले इसे खराब फाइल मिल गई। यदि आप यह नहीं जानते हैं, तो आप अभी भी अपनी डेटा फ़ाइल में कुछ प्रकार के आंशिक या ब्लॉक चेकसम या कुछ इसी तरह का निर्माण कर सकते हैं, जो डेटा अखंडता पर जोर देता है, इसलिए आप किसी प्रक्रिया के लिए जाने से पहले चीजों की जांच कर सकते हैं जो विफल हो सकती है। रोकथाम का एक औंस ...
जो

जवाबों:


21

यह निर्भर करता है कि पर्ल स्क्रिप्ट कितनी तेजी से लौटती है। यदि यह जल्दी लौटता है, तो आप CPU लोड से बचने के लिए निष्पादन के बीच एक छोटा सा विराम लगाना चाहते हैं, जैसे:

while true
do
  /someperlscript.pl
  sleep 1
done

यदि स्क्रिप्ट नहीं मिली है या तुरंत क्रैश हो जाता है तो यह सीपीयू हॉग को भी रोक देगा।

इन मुद्दों से बचने के लिए लूप को पर्ल लिपि में ही बेहतर तरीके से लागू किया जा सकता है।

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

जैसा कि आपने लिखा है कि लूप का उद्देश्य केवल यही है कि पर्ल स्क्रिप्ट को पुनरारंभ किया जाए, यह क्रैश हो जाए, एक बेहतर तरीका यह होगा कि इसे मॉनिटर की गई सेवा के रूप में लागू किया जाए लेकिन ऐसा करने का सटीक तरीका ओएस पर निर्भर है। जैसे: Solaris smf, Linux systemd या cron आधारित रेस्टोरर।


10
आप while sleep 1; do ...सच्चे कॉल को सहेजने के लिए कर सकते हैं ।
राफेल एहरेंस

4
@RaphaelAhrens वास्तव में हालांकि यह शुरुआती व्यवहार को थोड़ा बदल देगा। वैकल्पिक until ! sleep 1; do ...; doneअभी भी स्क्रिप्ट को शुरू करते समय उस अंतर्निहित कॉल को बचाएगा।
जूलियाग्रे

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

2
बेहतर: sleep 1& /someperlscript.pl; wait
user23013

2
@EliahKagan वेल स्पॉट किया गया। टीबीएच, मैं कभी भी untilनिर्देश का उपयोग नहीं करता हूं, मैंने इसे एक काल्पनिक do/untilलूप के साथ भ्रमित किया है जो शेल में मौजूद नहीं है।
जूलियाग्रे

13

उपयोग करने के बारे में अन्य उत्तर inotifyसही हैं, लेकिन इस प्रश्न का उत्तर नहीं है।

एक प्रक्रिया पर्यवेक्षक, जैसे कि supervisord, upstartया runit, अगर यह क्रैश होता है तो किसी सेवा को देखने और पुनः आरंभ करने की समस्या के लिए डिज़ाइन किया गया है।

आपका डिस्ट्रो संभवतः एक प्रक्रिया पर्यवेक्षक के साथ आता है जिसमें निर्मित किया जाता है।


11

while trueसामान्य प्रयोजन के रूप में ठीक है "हमेशा के लिए लूप" निर्माण। जैसा कि अन्य उत्तर कहते हैं, लूप का शरीर खाली नहीं होना चाहिए, या लूप के अंदर कमांड के गुण से खाली नहीं होना चाहिए।

यदि आप लिनक्स का उपयोग कर रहे हैं, तो आप एक कमांड का उपयोग करना चाह सकते हैं inotifywait, जो whileलूप को बहुत सरल बनाता है:

while inotifywait -qqe modify "$DIRECTORY"
do
    process_the_directory "$DIRECTORY"
done

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


`(apt-get or yum) inotify-tools '+1 कूल स्थापित करें!
जेजो मारा

4

1 को पर्ल स्क्रिप्ट में ले जाएं (@roaima सुझाव का पालन करें)

#!/usr/bin/perl

 use Linux::Inotify2;

 my $inotify = new Linux::Inotify2 or die "unable to inotify: $!";

 $inotify->watch ("Dir", IN_MODIFY, ## or in_{acess,create,open, etc...}
   sub { my $e = shift;
     my $name = $e->fullname;
     ## whatever 
     print "$name was modified\n" if $e->IN_MODIFY;
  });

 1 while $inotify->poll;

1
यह पुनरारंभ की आवश्यकता को संबोधित नहीं करता है, स्क्रिप्ट को क्रैश होना चाहिए या किसी कारण से मारा गया है।
जूलियाग्रे

@jlliagre, टिप्पणी के लिए धन्यवाद। जवाब में, मुझे किसी दुर्घटना या हत्या के बाद इच्छित व्यवहार के लिए स्पष्ट विनिर्देश नहीं दिख रहा है। यह स्पष्ट रूप से एक दिलचस्प और प्रासंगिक सवाल है। फिलहाल मैं इसे सरल
रखूंगा

@jlliagre यही अपवाद हैं। लेकिन पर्ल ऐसे मामले में सबसे उपयुक्त विकल्प नहीं हो सकता है क्योंकि यह अपवाद तंत्र का समर्थन नहीं करता है। सिर्फ एक अनुमान। अपवाद का समर्थन करने वाली भाषा में स्क्रिप्ट को पोर्ट करना सबसे अच्छा होगा। यह सब निर्भर करता है कि पोर्टिंग का काम कितना बड़ा है।

@ नशा, इन पर्ल, सिग्नल हैंडलर, एरर वैरिएबल, टियर :: टिनी आदि के साथ, हम कर सकते हैं! ... लेकिन - मैं अपवाद से निपटने और त्रुटि पुनर्प्राप्ति से नफरत करता हूं: वे कभी भी पूर्ण नहीं होते हैं ...
जोजो

1
@ जोजाओ मैं आपके साथ उन तथ्यों पर सहमत हूं जो त्रुटि पुनर्प्राप्ति शायद ही कभी पूरी हो। यह डेवलपर के लिए सभी संभावित मामलों को कवर करने के लिए है। तो क्या यह उद्योग जगत में पीएलसी के साथ है इसलिए यह सभी के बाद काफी संभव है; ;-)

3

जब आपकी पर्ल स्क्रिप्ट को हर समय चालू रखने का इरादा है, तो निर्माण का उपयोग क्यों करें? जब पर्ल कुछ गंभीर समस्या को देखते हुए विफल हो जाता है, तब तक शुरू की गई नई पर्ल स्क्रिप्ट बस दुर्घटनाग्रस्त हो सकती है। फिर और फिर-से-इतने पर।
यदि आप वास्तव में चाहते हैं कि आपका पर्ल शुरू हो जाए, तो क्रॉस्टैब और एक स्क्रिप्ट पर विचार करें, जो पहले चलने वाले उदाहरणों की जांच करती है। इस तरह आपकी स्क्रिप्ट रिबूट के बाद भी शुरू हो जाएगी।


2

सामान्य तौर पर while trueइसका उपयोग करने में कोई समस्या नहीं है क्योंकि यह एक छोटी परीक्षा है जिसे केवल पर्ल स्क्रिप्ट समाप्त होने के बाद निष्पादित किया जाता है। ध्यान रखें कि आप किस लिनक्स / यूनिक्स संस्करण का उपयोग कर रहे हैं, उसके आधार पर स्क्रिप्ट लॉगिंग बंद होने पर समाप्त हो सकती है। ऐसे मामले में एक स्क्रिप्ट में लूप का उपयोग करने पर विचार करें और इसे कॉल करें nohupऔर इसे पृष्ठभूमि में रखेंnohup myscript &

यदि पर्ल स्क्रिप्ट बहुत बार समाप्त हो जाती है और सीपीयू लोड का कारण बनता है तो यह लोड पर्ल स्क्रिप्ट के प्रति जवाबदेह है और नहीं while true

man nohupविवरण के लिए भी देखें।


एकमात्र समस्या गर्म लूप की क्षमता है जो सीपीयू उपयोग को बढ़ाती है। तो मैं पूरी तरह से इसे नीचे गिराने के लिए लूप के अंदर एक नींद कॉल लगाने से सहमत हूं।
क्रेग

2

यदि आप एक प्रक्रिया का प्रबंधन करना चाहते हैं, तो आप ऐसा करने के लिए एक प्रक्रिया प्रबंधक में देखना चाहते हैं।

कई हालिया प्रणालियों के साथ, आप अपनी प्रक्रियाओं की निगरानी के लिए systemd का उपयोग कर सकते हैं (जो शास्त्रीय init- लिपियों पर systemd के लाभों में से एक है)। अपनी पसंद के distro systemd का समर्थन नहीं करती हैं, तो आप इस्तेमाल कर सकते हैं daemontools या monit


monएक सरल विकल्प है, अगर मोनिट और सिस्टमड का लम्बरदार गले आपको उतना ही परेशान करते हैं जितना वे मुझे करते हैं।
एको

2

whileपाश वास्तव में एक अच्छा विचार नहीं है। वहाँ कोई बच नहीं है - यह सिर्फ हमेशा के लिए - सांख्यिकीय रूप से चलता है । पर्यावरण में कोई भी चीज बदल सकती है और यह प्रभावित नहीं होगी - और यह खराब हो सकती है।

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

और अगर, स्वर्ग की मनाही है, तो उस लूप को चलाने वाले शेल में कहीं भी एक मेमोरी लीक है - यहां तक ​​कि सबसे अधिक मिनट - यह बस लीक करना जारी रखेगा - सांख्यिकीय रूप से । यह अनियंत्रित निर्माण करेगा और एकमात्र सहारा इसे जबरदस्ती मारना है, फिर इसे बाद में करने के लिए बस शुरू करें।

यह वास्तव में वह तरीका नहीं है जिसे आपको एक पृष्ठभूमि वाली प्रक्रिया को सेट करना चाहिए - कम से कम, मेरी राय में नहीं। इसके बजाय, जैसा कि मुझे लगता है, एक रीसेट बिंदु होना चाहिए - स्क्रिप्ट और उसके राज्य का एक ताज़ा। ऐसा करने का सबसे आसान तरीका है exec। आप एक ही पीआईडी ​​को बनाए रखते हुए वर्तमान प्रक्रिया को एक नए के साथ बदल सकते हैं - लेकिन फिर भी एक नई प्रक्रिया चला रहे हैं ।

उदाहरण के लिए, यदि आपकी perlस्क्रिप्ट को कुछ मॉनीटर किए गए निर्देशिका में फ़ाइल संशोधन को सफलतापूर्वक हैंडल करने के बाद वापस लौटना चाहिए:

#!/bin/sh
trap 'rm -rf -- "${ldir%%*.}"' 0 INT
_exec() case    $#      in
        (0)     exec env -  "PID=$$" "ldir=${TMPDIR:-/tmp}/." \
                            "$0" "$@";;
        (*)     export "$@" "boff=0" "lmt=30"
                exec        "$0" "$@";;
        esac
[ "$PID" = "$$" ] || _exec
[ -w "$ldir" ]  &&
case    $ldir   in
(*.)    until   mkdir -- "$ldir"
        do      :& ldir=$ldir$$$!
        done    2>/dev/null
;;
(*)     until   /someperlscript.pl ||
                [ "$((boff+=1))"  -ge "$lmt" ]
        do      [ -d "$ldir" ]     &&
                sleep "$boff"      || ! break
        done
;;esac  &&      _exec ldir PID

...या कुछ इस तरह का। कुछ ऐसा है जो लूप के पीछे की मूलभूत मशीनरी को एक बार में हर बार ताज़ा करने की अनुमति देता है।


1

मैंने इनमें से कुछ उत्तरों को उकेरा है, लेकिन मैं सहज रूप से @ वाल्टरए के उत्तर के लिए सबसे गर्म भावनाएं रखता हूं। खैर, मैंने तब तक किया जब तक मैंने अपना जवाब नहीं दिया ...

व्यक्तिगत रूप से, मैं पर्ल स्क्रिप्ट को अपडेट करना चाहूंगा ताकि यह विफलता के बारे में एक वर्णनात्मक लॉग प्रविष्टि लिखता है और एक व्यवस्थापक को अलर्ट भेजता है।

यदि पर्ल स्क्रिप्ट को जारी रखने का मतलब है, फ़ाइल सिस्टम से बदलाव की प्रतीक्षा करना, तो यह विफल क्यों है?

यदि यह विफल नहीं है, तो आप इसे स्क्रिप्ट में लपेटने के बारे में चिंतित क्यों हैं कि इसे असीम रूप से फिर से शुरू करें?

यदि कोई कॉन्फ़िगरेशन समस्या या कुछ टूटी हुई निर्भरता है जो पर्ल स्क्रिप्ट को समाप्त करने का कारण बनती है, तो बस इसे फिर से शुरू करना और इसे अचानक काम करना शुरू करने की संभावना नहीं है।

आप पागलपन की परिभाषा जानते हैं, है ना? (बार-बार एक ही काम करना, एक अलग परिणाम की उम्मीद करना)। बस केह रहा हू। ;-)


हाहा- मुझे पता है, मुझे पता है। लेकिन आप जानते हैं - असली दुनिया बेकार है। वैसे भी - इसका कारण यह है कि यह फाइलों को प्रोसेस करता है, और कुछ फाइलें सही तरीके से ट्रांसमिट भी नहीं हो पाती हैं। हमें अभी तक विभिन्न कारणों की जानकारी नहीं है कि यह विफल हो सकता है। मैं त्रुटि को लॉग करने के बारे में आपकी बात देखता हूं, लेकिन मुझे अभी भी इसकी आवश्यकता होगी कि अगली फाइल को पर्यवेक्षक की तरह कुछ करके संसाधित किया जाए
अभिनव गुर्जर

यदि आप अपवादों को पकड़ सकते हैं, तो आप उन्हें लॉग इन कर सकते हैं, फिर प्रसंस्करण रख सकते हैं, और यहां तक ​​कि वापस भी जा सकते हैं और कभी-कभी विफल फ़ाइलों को पुनः प्रयास कर सकते हैं? हो सकता है कि विफल फ़ाइल को किसी अन्य उपयोगकर्ता या प्रक्रिया द्वारा बंद कर दिया गया था जब आपने इसे संसाधित करने का प्रयास किया था, आदि
क्रेग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.