কম্পিউটার

রুবিতে ইউনিক্স ডেমনের একটি তাত্ত্বিক ভূমিকা

ইউনিক্স ডেমন এমন প্রোগ্রাম যা ব্যাকগ্রাউন্ডে চলে। Nginx, Postgres এবং OpenSSH হল কয়েকটি উদাহরণ। তারা তাদের প্রক্রিয়াগুলিকে "বিচ্ছিন্ন" করার জন্য কিছু বিশেষ কৌশল ব্যবহার করে এবং তাদের যেকোনো টার্মিনাল থেকে স্বাধীনভাবে চলতে দেয়।

আমি সবসময় ডেমনের প্রতি একধরনের মুগ্ধ ছিলাম - সম্ভবত এটির নাম - এবং আমি ভেবেছিলাম যে তারা কীভাবে কাজ করে তা ব্যাখ্যা করে একটি পোস্ট করা মজাদার হবে। এবং বিশেষভাবে, আপনি কিভাবে রুবিতে সেগুলি তৈরি করতে পারেন৷

...কিন্তু প্রথমে।

এটি বাড়িতে চেষ্টা করবেন না!

আপনি সম্ভবত একটি ডেমন তৈরি করতে চান না। কাজটি সম্পন্ন করার অনেক সহজ উপায় আছে।

আপনি একটি প্রোগ্রাম তৈরি করতে চাইতে পারেন যা ব্যাকগ্রাউন্ডে চলে। সমস্যা নেই. আপনার ওএস একটি সিস্টেম প্রদান করে যা আপনাকে ব্যাকগ্রাউন্ডে স্বাভাবিক প্রোগ্রাম চালাতে দেয়।

উবুন্টুতে, এটি সিস্টেমডের আপস্টার্টের মাধ্যমে সম্পন্ন হয়। ওএসএক্সে এটি চালু হয়েছে। অন্যরাও আছে। কিন্তু তারা সবাই একই ধারণা অনুযায়ী কাজ করে। আপনি একটি কনফিগারেশন ফাইল প্রদান করেন যেটি সিস্টেমকে বলে যে কিভাবে দীর্ঘ-চলমান প্রোগ্রামটি শুরু এবং বন্ধ করতে হয়। তারপর...ওয়েল, এটা মোটামুটি. আপনি 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

কাঁটাচামচের কলের ফলে একই কোড চালানোর দুটি প্রক্রিয়া হয়। মূল প্রক্রিয়াটি নতুন প্রক্রিয়ার মূল। ফর্ক পিতামাতার জন্য একটি সত্য মান এবং সন্তানের জন্য একটি মিথ্যা মান প্রদান করে। তাই exit if fork() শুধুমাত্র অভিভাবক থেকে প্রস্থান করে৷

বর্তমান সেশন থেকে বিচ্ছিন্ন করা

আমাদের "ডেমনাইজেশন" কোডে কয়েকটি সমস্যা রয়েছে। যদিও এটি সফলভাবে প্রক্রিয়াটিকে অনাথ করে,  এটি এখনও টার্মিনালের সেশনের অংশ। এর মানে হল যে আপনি যদি টার্মিনালকে হত্যা করেন তবে আপনি ডেমনকে হত্যা করবেন। এটি ঠিক করার জন্য, আমাদের একটি নতুন সেশন তৈরি করতে হবে এবং পুনরায় কাঁটাচামচ করতে হবে। ইউনিক্স সেশন গ্রুপের সাথে পরিচিত নন? এখানে একটি ভাল স্ট্যাকওভারফ্লো পোস্ট।

# 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 এক্সটেনশন থেকে প্রসেস মডিউলে লাইনের জন্য এটির লাইনটি অনুলিপি করেছি যা Rails 4.x এ সরানো হয়েছিল। আপনি এখানে সেই পদ্ধতি দেখতে পারেন।


  1. রুবিতে ল্যাম্বডাস ব্যবহার করা

  2. ইউনিকর্ন কীভাবে এনজিনক্সের সাথে কথা বলে - রুবিতে ইউনিক্স সকেটগুলির একটি ভূমিকা

  3. রুবিতে নিউরাল নেটওয়ার্ক:একটি এত ভীতিকর ভূমিকা নয়

  4. রুবি 2.6-এ 9টি নতুন বৈশিষ্ট্য