Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी में यूनिक्स डेमॉन को समझें: एक सैद्धांतिक गाइड

यूनिक्स डेमॉन वे प्रोग्राम होते हैं जो बैकग्राउंड में चलते हैं। Nginx, Postgres और OpenSSH कुछ उदाहरण हैं। वे अपने प्रोसेस को "डिटैच" करने के लिए कुछ विशेष तरकीबों का उपयोग करते हैं, और उन्हें किसी भी टर्मिनल से स्वतंत्र रूप से चलने देते हैं।

मैं हमेशा से डेमॉन के प्रति थोड़ा आकर्षित रहा हूँ - शायद नाम की वजह से - और मुझे लगा कि यह दिखाना मजेदार होगा कि वे कैसे काम करते हैं। और विशेष रूप से, आप उन्हें रूबी में कैसे बना सकते हैं।

...लेकिन पहले।

इसे घर पर आज़माने की कोशिश न करें!

आप शायद डेमॉन नहीं बनाना चाहते। काम पूरा करने के बहुत आसान तरीके हैं।

आप शायद ऐसा प्रोग्राम चाहते हैं जो बैकग्राउंड में चले। कोई बात नहीं। आपका OS सामान्य प्रोग्राम को बैकग्राउंड में चलाने के लिए एक सिस्टम प्रदान करता है।

उबंटू पर, यह Upstart या systemd के माध्यम से होता है। OSX पर यह launchd है। अन्य भी हैं। लेकिन वे सभी एक ही अवधारणा के अनुसार काम करते हैं। आप एक कॉन्फिगरेशन फाइल प्रदान करते हैं जो सिस्टम को बताती है कि लंबे समय तक चलने वाले प्रोग्राम को कैसे शुरू और बंद करना है। फिर... ठीक है, बस इतना ही। आप service my_app start जैसे सिस्टम कमांड का उपयोग करके प्रोग्राम शुरू कर सकते हैं और यह बैकग्राउंड में चलता है।

संक्षेप में, अपस्टार्ट सरल और विश्वसनीय है जबकि पुराने स्कूल के डेमॉन गूढ़ और सही करना बहुत कठिन हैं।

...लेकिन अगर ऐसा है, तो हमें डेमॉन के बारे में क्यों सीखना चाहिए? खैर, क्योंकि मज़ा! और हम रास्ते में यूनिक्स प्रोसेस के बारे में कुछ दिलचस्प तथ्य सीखेंगे।

सबसे सरल डेमॉन

अब जब आपको कभी डेमॉन न बनाने के लिए कहा गया है, तो आइए कुछ डेमॉन बनाते हैं! रूबी 1.9 के बाद से, यह अविश्वसनीय रूप से सरल है। आपको बस Process.daemon मेथड का उपयोग करना है।

# Optional: set the process name to something easy to type<br>$PROGRAM_NAME = "rubydaemon"<br> # Make the current process into a daemon Process.daemon() # Once per second, log the current time to a file loop do File.open("/tmp/rubydaemon.log", "a") { |f| f.puts(Time.now) } sleep(1) end 

अब, जब मैं इस स्क्रिप्ट को चलाता हूँ, तो कंट्रोल कंसोल पर वापस आ जाता है। अगर मैं अपना लॉग टेल करता हूँ, तो मैं देख सकता हूँ कि टाइमस्टैम्प हर सेकंड जोड़ा जा रहा है, जैसा कि मुझे उम्मीद थी।

रूबी में यूनिक्स डेमॉन को समझें: एक सैद्धांतिक गाइड

तो यह आसान था। लेकिन यह अभी भी समझाता नहीं है कि डेमॉन कैसे काम करते हैं। इसे वास्तव में समझने के लिए, हमें डेमोनाइजेशन को मैन्युअली करना होगा।

पेरेंट प्रोसेस बदलना

यदि आप सामान्य प्रोग्राम चलाने के लिए बैश का उपयोग करते हैं, तो उस प्रोग्राम का प्रोसेस बैश का चाइल्ड होता है। लेकिन डेमॉन के साथ, इससे कोई फर्क नहीं पड़ता कि आप उन्हें कैसे लॉन्च करते हैं। उनका पेरेंट प्रोसेस हमेशा OS द्वारा प्रदान किया गया "रूट" प्रोसेस होता है।

आप यह डेमॉन के पेरेंट आईडी को देखकर बता सकते हैं। एक डेमॉन का पेरेंट आईडी हमेशा 1 होता है। नीचे दिए गए उदाहरण में हम इसे दिखाने के लिए pstree का उपयोग करते हैं:

$ pstree -+= 00001 root /sbin/launchd |--- 72314 snhorne rubydaemon 

दिलचस्प बात यह है कि "अनाथ प्रोसेस" भी ऐसे ही दिखते हैं। एक अनाथ प्रोसेस एक चाइल्ड प्रोसेस होता है जिसका पेरेंट समाप्त हो गया है।

तो, डेमॉन बनाने के लिए हमें जानबूझकर एक प्रोसेस को अनाथ बनाना होगा। नीचे दिया गया कोड ऐसा करता है।

# Optional: set the process name to something easy to type $PROGRAM_NAME = "rubydaemon" # Create a new child process and exit the parent. This "orphans" # our process and creates a daemon. exit if fork() # Once per second, log the current time to a file loop do File.open("/tmp/rubydaemon.log", "a") { |f| f.puts(Time.now) } sleep(1) end 

fork की कॉल के परिणामस्वरूप दो प्रोसेस एक ही कोड चलाते हैं। मूल प्रोसेस नए प्रोसेस का पेरेंट होता है। Fork पेरेंट के लिए ट्रूथी मान और चाइल्ड के लिए फाल्सी मान लौटाता है। इसलिए exit if fork() केवल पेरेंट को बाहर निकालता है।

वर्तमान सत्र से डिटैच होना

हमारे "डेमोनाइजेशन" कोड में कुछ समस्याएं हैं। हालांकि यह सफलतापूर्वक प्रोसेस को अनाथ बनाता है, यह अभी भी टर्मिनल के सत्र का हिस्सा है। इसका मतलब है कि अगर आप टर्मिनल को मारते हैं, तो आप डेमॉन को मार देते हैं। इसे ठीक करने के लिए, हमें एक नया सत्र बनाना होगा और फिर से फोर्क करना होगा। यूनिक्स सत्र समूहों से परिचित नहीं हैं? यहां एक अच्छा StackOverflow पोस्ट है।

# Optional: set the process name to something easy to type $PROGRAM_NAME = "rubydaemon" # Create a new child process and exit the parent. This "orphans" # our process and creates a daemon. exit if fork # Create a new session, create a new child process in it and # exit the current process. Process.setsid exit if fork # Once per second, log the current time to a file loop do File.open("/tmp/rubydaemon.log", "a") { |f| f.puts(Time.now) } sleep(1) end 

STDIN, STDOUT और STDERR को पुनर्निर्देशित करना

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

लेकिन आप वास्तव में STDIN, STDOUT, और STDERR को किसी भी पथ पर पुनर्निर्देशित कर सकते हैं। यहां हम /dev/null पर पुनर्निर्देशित करते हैं।

# Optional: set the process name to something easy to type $PROGRAM_NAME = "rubydaemon" # Create a new child process and exit the parent. This "orphans" # our process and creates a daemon. exit if fork # Create a new session, create a new child process in it and # exit the current process. Process.setsid exit if fork STDIN.reopen "/dev/null" STDOUT.reopen "/dev/null", "a" STDERR.reopen '/dev/null', 'a' # Once per second, log the current time to a file loop do File.open("/tmp/rubydaemon.log", "a") { |f| f.puts(Time.now) } sleep(1) end 

कार्य निर्देशिका बदलना

अंत में, डेमॉन की कार्य निर्देशिका वही होती है जिसमें हम इसे चलाते समय थे। यह शायद सबसे अच्छा विचार नहीं है, क्योंकि मैं बाद में उस निर्देशिका को हटाने का फैसला कर सकता हूँ। तो चलिए निर्देशिका को / पर बदलते हैं।

# Optional: set the process name to something easy to type $PROGRAM_NAME = "rubydaemon" # Create a new child process and exit the parent. This "orphans" # our process and creates a daemon. exit if fork # Create a new session, create a new child process in it and # exit the current process. Process.setsid exit if fork STDIN.reopen "/dev/null" STDOUT.reopen "/dev/null", "a" STDERR.reopen '/dev/null', 'a' Dir.chdir("/") # Once per second, log the current time to a file loop do File.open("/tmp/rubydaemon.log", "a") { |f| f.puts(Time.now) } sleep(1) end 

क्या मैंने इसे पहले देखा है?

चरणों का यह क्रम मूल रूप से वही है जो हर रूबी डेमॉन को Process.daemon मेथड के रूबी कोर में जोड़े जाने से पहले करना पड़ता था। मैंने इसे ActiveSupport के Process मॉड्यूल के एक्सटेंशन से लगभग लाइन दर लाइन कॉपी किया है जिसे Rails 4.x में हटा दिया गया था। आप उस मेथड को यहां देख सकते हैं।


  1. यूनिकॉर्न को Nginx से जोड़ें: रूबी में यूनिक्स सॉकेट के लिए एक व्यावहारिक गाइड यूनिकॉर्न को Nginx से जोड़ें: रूबी में यूनिक्स सॉकेट के लिए एक व्यावहारिक गाइड

    रूबी एप्लिकेशन सर्वर आमतौर पर Nginx जैसे वेब सर्वर के साथ उपयोग किए जाते हैं। जब कोई उपयोगकर्ता आपके रेल्स ऐप से कोई पेज अनुरोध करता है, तो Nginx अनुरोध को एप्लिकेशन सर्वर को सौंप देता है। लेकिन वास्तव में यह कैसे काम करता है? Nginx यूनिकॉर्न से कैसे बात करता है? सबसे कुशल विकल्पों में से एक है यूनि

  1. रूबी में न्यूरल नेटवर्क को समझना: एक शुरुआती गाइड रूबी में न्यूरल नेटवर्क को समझना: एक शुरुआती गाइड

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

  1. Ruby 2.6 में 9 प्रमुख संवर्द्धन का अन्वेषण Ruby 2.6 में 9 प्रमुख संवर्द्धन का अन्वेषण

    Ruby का एक नया संस्करण नई सुविधाओं और प्रदर्शन सुधारों के साथ आ रहा है। क्या आप परिवर्तनों के साथ बने रहना चाहेंगे? आइए एक नज़र डालते हैं! अंतहीन रेंज (Endless Ranges) Ruby 2.5 और पुराने संस्करण पहले से ही अंतहीन रेंज का एक रूप (Float::INFINITY के साथ) का समर्थन करते हैं, लेकिन Ruby 2.6 इसे अगले स्त