12 पॉइंट द्वारा GN⁺ 2025-05-27 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Bash स्क्रिप्ट में वेब सर्वर की स्थिति जांचने के लिए बार-बार कनेक्शन प्रयास करने पर सर्वर अप्रत्याशित रूप से अनंत लूप में फंस सकता है
  • इसे हल करने के लिए इस्तेमाल होने वाला टूल timeout कमांड के चलने की समय-सीमा तय करता है, और सीमा पार होने पर सिग्नल भेजकर प्रोसेस समाप्त करने की कोशिश करता है
  • until जैसे shell built-in पर इसे सीधे लागू नहीं किया जा सकता, इसलिए bash प्रोसेस रैपिंग या स्क्रिप्ट को अलग करने के जरिए इसे हल किया जा सकता है

Bash स्क्रिप्ट में वेब सर्वर का इंतज़ार और अनंत लूप की समस्या

  • व्यवहारिक कामों में Bash स्क्रिप्ट का उपयोग करके वेब सर्वर सेटअप और स्टेटस चेक किया जाता है
  • संरचना ऐसी होती है कि सर्वर चालू होने तक अगला काम रोका जाता है, और सामान्यतः यह बिना समस्या के काम करती है
  • लेकिन सर्वर शुरू होते समय क्रैश हो जाए तो यह अनंत लूप में फंस सकता है, इसलिए समाधान की ज़रूरत पड़ती है

until के उपयोग का उदाहरण और उसकी सीमा

  • नीचे जैसे सिंटैक्स से वेब सर्वर health check को बार-बार चलाया जाता है
    until curl --silent --fail-with-body 10.0.0.1:8080/health; do  
    	sleep 1  
    done  
    
  • सर्वर फेल होने पर sleep 1 हमेशा चलता रहता है जैसी स्थिति बन जाती है

timeout utility का परिचय

  • timeout कमांड किसी कमांड के तय समय के भीतर पूरा न होने पर सिग्नल (SIGTERM आदि) भेजकर उसे समाप्त करता है
  • उदाहरण: timeout 1s sleep 5 में 1 सेकंड बाद sleep प्रोसेस को समाप्त करने की कोशिश की जाती है
  • समाप्ति पर यह असामान्य exit code (जैसे 124) लौटाता है

timeout और until को साथ उपयोग करने की कोशिश और समस्या

  • स्वाभाविक रूप से timeout और until को नीचे की तरह साथ इस्तेमाल करने की कोशिश की जा सकती है
    timeout 1m until curl ...; do  
    	sleep 1  
    done  
    
  • लेकिन timeout प्रोसेस को लक्ष्य बनाकर सिग्नल भेज सकता है, जबकि until shell का built-in कीवर्ड है, इसलिए इसे सीधे लागू नहीं किया जा सकता

समाधान: Bash प्रोसेस रैपिंग या बाहरी स्क्रिप्ट का उपयोग

  • पूरे until लूप को bash -c से रैप करके अलग प्रोसेस के रूप में चलाया जाए तो timeout लागू किया जा सकता है
    timeout 1m bash -c "until curl ...; do sleep 1; done"  
    
  • या लूप वाले हिस्से को अलग Bash स्क्रिप्ट में निकालकर उस स्क्रिप्ट पर timeout लागू किया जा सकता है
    timeout 1m ./until.sh  
    
  • shell built-in पर timeout सीधे लागू नहीं होता, लेकिन ऊपर दिए गए तरीकों से वांछित व्यवहार हासिल किया जा सकता है

1 टिप्पणियां

 
GN⁺ 2025-05-27
Hacker News राय
  • मेरी सबसे पसंदीदा कम-ज्ञात ट्रिक्स में से एक है strace fault injection का उपयोग करके अलग-अलग system call failures को टेस्ट करने का तरीका

    $ strace -e trace=clone -e fault=clone:error=EAGAIN
    

    संबंधित लिंक में इसका और विस्तृत विवरण दिया गया है

    • यह फीचर वाकई कमाल का लगता है, और काश यह पहले से पता होता, ऐसा अनुभव साझा किया
      failure branch को टेस्ट करने का तरीका नहीं होने पर वे अक्सर function के कुछ हिस्सों को अस्थायी कोड से बदल देते थे, लेकिन इस ट्रिक से अधिक संक्षिप्त तरीका संभव लगता है

    • राय है कि यह तरीका सच में बहुत उपयोगी लगता है
      साथ ही यह जिज्ञासा जताई कि क्या Windows में भी ऐसा कोई समान फीचर है

  • service health check में सबसे अच्छा तरीका यह है कि maximum timeout duration और maximum retry count दोनों सेट किए जाएँ
    आम तौर पर X बार तक retry किया जाता है, और अधिकतम Y समय के भीतर failure मान लिया जाता है
    बहुत देर तक इंतज़ार करने के बजाय जितना जल्दी हो सके failure तय करने की ज़रूरत पर ज़ोर
    standard services में container dependencies पर्याप्त रूप से सुनिश्चित होने और ready होने के बाद ही health check शुरू करना चाहिए
    Kubernetes में Init Container, AWS ECS में dependsOn, Docker Compose में depends_on सेटिंग का संदर्भ दिया गया
    POSIX shell script का उदाहरण दिया गया
    लेकिन यह भी कहा गया कि curl में यह फीचर पहले से built-in है, इसलिए अलग script के बिना इसे इस तरह इस्तेमाल किया जा सकता है

    curl --silent --fail-with-body --connect-timeout 5 --retry-all-errors --retry-delay 1 --retry-max-time 300 --retry 300 10.0.0.1:8080/health
    
  • Mac पर timeout कमांड डिफ़ॉल्ट रूप से उपलब्ध नहीं होती, इसलिए केवल bash builtins से timeout लागू करने की कई कोशिशें करने का अनुभव साझा किया
    यह समझाया कि sleep कमांड POSIX में standard है, इसलिए उसका उपयोग किया जा सकता है
    नीचे timeout फीचर लागू करने का उदाहरण दिया गया

    # TIMEOUT SYSTEM(सारांश)
    # function timeout <num_seconds> <command>
    # निश्चित समय बीतने के बाद <command> ट्रिगर करें
    

    times_up नाम की function से timeout handle किया गया
    10 सेकंड timeout के साथ for loop को 20 बार चलाकर टेस्ट करने का उदाहरण दिया गया

    • 12 साल पहले Stack Overflow की सलाह के आधार पर ऐसा ही तरीका लागू करने का अनुभव साझा किया
      संदर्भ लिंक में विस्तृत जानकारी देखी जा सकती है
      ज़ोर दिया गया कि इसमें केवल shell builtins और sleep का उपयोग हुआ था, और वह कोड POSIX-compatible होना अनिवार्य था
      यह भी बताया गया कि उदाहरण में bash का {1..20} syntax POSIX नहीं है, इसलिए सावधानी ज़रूरी है
      मेरा सुधार यह था कि timeout न होने पर true और timeout होने पर false लौटे, ताकि script में error handling आसान हो सके

    • नीचे की तरह command और sleep को parallel चलाकर, तय समय बीतने पर signal से command को बंद करने का बहुत सरल तरीका साझा किया गया

      <command> & sleep <timeout>; kill -SIGALRM %1
      
    • 13 साल पहले read -t का उपयोग करके timeout लागू करने वाली script का उदाहरण साझा किया गया
      लिंक

  • curl में पहले से --retry-connrefused फ्लैग मौजूद है, इसलिए shell loop के बिना भी इस फीचर का सीधा उपयोग किया जा सकता है

  • bash -c का उपयोग करते समय अगर variables पास करने हों, तो नीचे की तरह arguments जोड़ने की सलाह दी गई

    bash -c 'some command "$1" "$2"' -- "$var1" "$var2"
    

    "--" का उपयोग क्यों किया जाता है और argv[0] की क्या भूमिका है, यह समझाया गया
    यह भी कहा गया कि printf %q का उपयोग किया जा सकता है, लेकिन Bourne-compatible तरीका अधिक पसंद है

    • समझाया गया कि "--" का मतलब bash और अधिकांश Unix/Linux CLI में option termination signal के रूप में बहुत स्पष्ट है
      संबंधित संदर्भ

    • साझा किया गया कि Busybox argv[0] के मान के आधार पर चलाए जाने वाले program का निर्णय करता है, इसलिए इसे "ls", "mv", "cp" जैसे इच्छित command के रूप में सेट किया जा सकता है

  • जब retry logic की ज़रूरत होती है, तो मैं आम तौर पर नीचे जैसा तरीका इस्तेमाल करता हूँ

    for i in {0..60}; do
      true -- "$i"
      if eventually_succeeds; then break; fi
      sleep 1s
    done
    

    यह बहुत polished नहीं है, लेकिन आम तौर पर सही काम करता है, और अगला उन्नत कदम exponential backoff लागू करना हो सकता है
    scalability के लिहाज़ से भी इसका फायदा है

    • shellcheck इस स्थिति में _ variable का उपयोग करके इसे संभालने की सलाह देता है
      संदर्भ लिंक

    • इस बात पर ज़ोर दिया गया कि eventually_succeeds function को स्थिति के अनुसार timeout या अतिरिक्त defensive coding की ज़रूरत पड़ सकती है
      POSIX/process/IO में हमेशा defensive code लिखने की ज़रूरत याद दिलाई गई

  • अतीत में जब बच्चे छोटे थे, तब 30 मिनट तक केवल एक प्रोग्राम देखने की अनुमति देने के लिए नीचे दिए गए command को एक तरह के parental control tool की तरह इस्तेमाल करने का अनुभव साझा किया गया

    timeout 1800 mplayer show.mp4 ; sudo pm-suspend
    

    इसे बहुत उपयोगी आइडिया बताया गया

    • यह राय भी जोड़ी गई कि उपयोग का यह उदाहरण सबसे शानदार तरीके से समझाया गया है
  • यह बताया गया कि subprocess को signal भेजना पड़ता है, इसलिए command inline या temporary script file का उपयोग ज़्यादा पसंद नहीं है
    मेरी पसंदीदा विधि यह है कि ज़रूरी complex logic को एक function में लिखा जाए, उसे export किया जाए, और फिर timeout bash -c से wrap किया जाए
    यह aidenn0 द्वारा बताई गई safe argument passing विधि से जुड़ा है

    #!/usr/bin/env bash
    
    long_fn () { # 원하는 논리 구현
     sleep $1
    }
    to () {
     local duration="$1"; shift
     local fn_name="$1"; shift
     export -f "$fn_name"
     timeout "$duration" bash -c "$fn_name"' "$@"' _ $@
    }
    
    time to 1s long_fn 5
    
    • यह इंगित किया गया कि अंत में "$@" ज़रूर लिखना चाहिए
      नहीं तो spaces वाले arguments सही तरह से pass नहीं होंगे
      इसे जाँचने के लिए long_fn का उदाहरण भी साझा किया गया
  • पहले timeout पर लिखी गई एक blog post का ज़िक्र किया गया
    अगर shell के बजाय सामान्य programming language या अंदरूनी कार्यप्रणाली में अधिक रुचि हो, तो संबंधित ब्लॉग देखने की सलाह दी गई

  • Kubernetes setup में command timeout जोड़ने का अनुभव साझा किया गया
    await-cmd.sh, await-http.sh, await-tcp.sh जैसी POSIX shell scripts परिपक्व हैं और कुछ स्थितियों में काफ़ी उपयोगी हो सकती हैं
    संबंधित project लिंक