কম্পিউটার টিউটোরিয়াল

রুবিতে ইউনিক্স ডেমন বোঝা: একটি থিয়োরেটিক্যাল গাইড

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

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

...আর তার আগে।

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

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

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

উবুন্টুতে, এটি Upstart বা systemd দিয়ে অ্যাকম্পলিশ হয়। OSX-এ এটি launchd। আরো আছে। কিন্তু সেগুলো সব একই কনসেপ্ট অনুযায়ী কাজ করে। আপনি একটি কনফিগারেশন ফাইল প্রদান করেন যা সিস্টেমকে বলে লং-রানিং প্রোগ্রামটি কীভাবে স্টার্ট এবং স্টপ করবে। তারপর...এটো মুটামুটি সেটি। আপনি প্রোগ্রামটি একটি সিস্টেম কমান্ড দিয়ে স্টার্ট করতে পারেন যেমন service my_app start এবং এটি ব্যাকগ্রাউন্ডে রান করে।

সংক্ষেপে, upstart সিম্পল এবং রিলায়েবল যেখানে ওল্ড-স্কুল ডেমনগুলো আর্কেন এবং খুব কঠিন সঠিকভাবে বানানো।

...তবে যদি এটাই সত্য হয়, তবে আমরা ডেমন সম্পর্কে কেন শিখব? কারণ মজা! এবং আমরা ইউনিক্স প্রসেসের কিছু ইন্টেরেস্টিং ফ্যাক্ট শিখব।

সबচেয়ে সিম্পল ডেমন

এখন যেহেতু আপনাকে বলা হয়েছে ডেমন বানাবেন না, চলুন কিছু ডেমন বানাই! রুবি 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 

এখন, যখন আমি এই স্ক্রিপ্টটি রান করি, কন্ট্রোল কনসোলে ফিরে যায়। আমি আমার লগ টেইল করলে দেখি টাইমস্ট্যাম্প প্রতি সেকেন্ডে যোগ হচ্ছে, ঠিক যেমন আমি আশা করলাম।

রুবিতে ইউনিক্স ডেমন বোঝা: একটি থিয়োরেটিক্যাল গাইড

এটো সহজ ছিল। কিন্তু এটি এখনো ব্যাখ্যা করে না ডেমন কীভাবে কাজ করে। সেটি সত্যিকারের বুঝতে হলে, আমাদের ডেমনাইজেশন ম্যানুয়ালি করতে হবে।

পেরেন্ট প্রসেস পরিবর্তন করা

আপনি যদি bash ব্যবহার করে একটি নরমাল প্রোগ্রাম রান করেন, সেই প্রোগ্রামের প্রসেস bash-এর চাইল্ড। কিন্তু ডেমনদের সাথে, এটা ম্যাটার করে না আপনি সেগুলো কীভাবে লঞ্চ করেছেন। তাদের পেরেন্ট প্রসেস সবসময় OS-দ্বারা প্রদত্ত "রুট" প্রসেস।

আপনি এটি বুঝতে পারেন ডেমন-এর পেরেন্ট আইডি দেখে। একটি ডেমন-এর পেরেন্ট আইডি সবসময় 1। নিচের উদাহরণে আমরা pstree ব্যবহার করে এটি দেখাচ্ছি:

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

আশার্যিকরভাবে, এটি "orphaned processes"-র মতও দেখায়। একটি orphaned process হলো একটি চাইল্ড প্রসেস যার পেরেন্ট টার্মিনেট হয়েছে।

তাহলে, একটি ডেমন বানাতে হলে আমাদের ইন্টেনশনালি একটি প্রসেসকে orphan করতে হবে। নিচের কোডটি এটি করে।

# 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 পেরেন্টের জন্য truthy ভ্যালু এবং চাইল্ডের জন্য falsy ভ্যালু রিটার্ন করে। তাই exit if fork() শুধু পেরেন্টকে এক্সিট করে।

কারেন্ট সেশন থেকে ডিট্যাচ করা

আমাদের "ডেমনাইজেশন" কোডটির কয়েকটা সমস্যা রয়েছে। যদিও এটি সফলভাবে প্রসেসকে orphan করে, এটি এখনো টার্মিন্যালের সেশনের অংশ। এর মানে যদি আপনি টার্মিন্যাল কিল করেন, তবে আপনি ডেমনকেও কিল করবেন। এটিকে ফিক্স করতে, আমাদের একটি নতুন সেশন তৈরি করতে হবে এবং আবার ফর্ক করতে হবে। ইউনিক্স সেশন গ্রুপস সাথে পরিচিত নন? এখানে একটি ভালো 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 মডিউলে এক্সটেনশন থেকে যা রেলস 4.x-এ রিমুভ করা হয়েছিল। আপনি সেটি এখানে দেখতে পারেন।


  1. রুবিতে ল্যাম্বডা মাস্টার করুন: বেসিক থেকে অ্যাডভান্সড টেকনিক

  2. Unicorn কে Nginx-এ কানেক্ট করা: রুবিতে ইউনিক্স সকেটের প্র্যাক্টিক্যাল গাইড

  3. রুবিতে নিউরাল নেটওয়ার্ক ডিমিস্টিফাই: শুরুকারীদের গাইড

  4. রুবি ২.৬-এ ৯টি গুরুত্বপূর্ণ উন্নতির অন্বেষণ