systemd نے آپ کی سروس restart کیوں نہیں کی؟
Restart= صرف main process کو دیکھتا ہے؛ اسی cgroup میں dead child نظر نہیں آتا۔ Type=، restart limits اور journal کے کام کرنے کا درست طریقہ جانیں۔
مختصر جواب: systemd کی restart policies ہر unit کے ایک process کی نگرانی کرتی ہیں
systemd کی restart policies ہر unit کے ایک process، یعنی main process، کی نگرانی کرتی ہیں۔ Restart= صرف اسی ایک process کا exit status پڑھتا ہے، کسی اور process کا نہیں۔ کسی unit کے control group میں بیس processes ہو سکتے ہیں۔ ان میں سے ایک process ختم ہو جائے، تب بھی unit active (running) رہتی ہے کیونکہ main process اب بھی موجود ہوتا ہے۔ systemd کے لحاظ سے کچھ ناکام نہیں ہوا، اس لیے کچھ restart نہیں کیا جاتا۔
systemd کو دوسرے processes کا علم ضرور ہوتا ہے۔ unit رکنے پر یہ انہیں ختم کرتا ہے، ان کی memory کو unit کی limits میں شمار کرتا ہے، ان پر unit کا CPU quota لاگو کرتا ہے، اور انہیں systemctl status میں دکھاتا ہے۔ لیکن یہ ان processes کا exit status کبھی نہیں پڑھتا۔ restart logic اور cgroup دو الگ چیزیں ہیں، اور اس guide کا زیادہ تر حصہ ان دونوں کے درمیان موجود خلا سے متعلق ہے۔
cgroup میں کیا شامل ہوتا ہے، اور restart logic کیا پڑھتا ہے
cgroup (control group) ایک kernel object ہے جو processes کے ایک مجموعے کا مالک ہوتا ہے۔ ہر service unit کو ایک cgroup ملتا ہے، جس کا نام unit کے نام پر ہوتا ہے۔ کوئی process اس سے باہر نہیں جا سکتا۔ Child processes اپنے parent کا cgroup inherit کرتے ہیں، اور unprivileged process خود کو کسی دوسرے cgroup میں منتقل نہیں کر سکتا۔ اسی لیے systemd ایسے daemon کو بھی مکمل طور پر ختم کر سکتا ہے جو دو مرتبہ fork کرے، جبکہ پرانے init scripts یہ کام قابلِ اعتماد طریقے سے نہیں کر سکتے تھے۔
دونوں حقائق کو ساتھ رکھ کر دیکھیں:
systemd-cgls --unit myapp.service
systemctl show -p MainPID -p NRestarts -p Restart -p RestartUSec myapp.servicesystemd-cgls unit کے تمام processes دکھاتا ہے۔ MainPID وہ واحد number ہے جسے restart policy پڑھتی ہے۔ جب یہ دونوں آپ کے ذہنی model سے مطابقت نہ رکھیں تو یہی اختلاف bug ہوتا ہے۔ MainPID=0، غلط PID سے بھی زیادہ سنگین ہے: اس کا مطلب ہے کہ systemd کسی چیز کو track ہی نہیں کر رہا، اس لیے کوئی Restart= value کبھی trigger نہیں ہو سکتی۔
main-process rule کی ایک حقیقی exception موجود ہے۔ اگر kernel کا out-of-memory killer unit کے cgroup کے اندر موجود کسی process کو ختم کر دے تو systemd اسے دیکھ لیتا ہے، کیونکہ وہ cgroup کی memory.events file کو monitor کرتا ہے۔ OOMPolicy= طے کرتا ہے کہ اس کے بعد کیا ہوگا، اور اس کی default value stop ہے: پورا unit stop ہو جاتا ہے، نتیجہ oom-kill کے طور پر record ہوتا ہے، اور اسے failure شمار کیا جاتا ہے، اس لیے Restart=on-failure trigger ہوتا ہے۔ journal میں یہ بات واضح طور پر درج ہوتی ہے۔
myapp.service: A process of this unit has been killed by the OOM killer.
myapp.service: Failed with result 'oom-kill'.لہٰذا memory کی وجہ سے ختم کیا گیا child unit کو ضرور down کرتا ہے، جبکہ segmentation fault سے ختم ہونے والے اسی child کی موت unit کو down نہیں کرتی۔ اگر آپ unit پر memory limits مقرر کرتے ہیں تو restart policy کو tune کرنے سے پہلے دیکھیں کہ MemoryMax اور CPUQuota unit کے cgroup پر کیسے لاگو ہوتے ہیں، کیونکہ یہ دونوں features اسی مقام پر ایک دوسرے سے متعلق ہوتے ہیں اور کہیں اور نہیں۔
Type= کس طرح مرکزی process منتخب کرتا ہے
Type= سیکشن میں [Service] صرف startup ordering سے متعلق نہیں ہے۔ یہی وہ اصول ہے جو طے کرتا ہے کہ کون سا PID (process ID) MainPID بنے گا، اور یوں یہ بھی طے ہوتا ہے کہ Restart= کیا دیکھ سکتا ہے۔
Type=simpledefault ہے۔ systemd جس process کوExecStart=سے fork کرتا ہے، وہ main process ہوتا ہے۔ systemd unit کو فوراً started mark کر دیتا ہے، اس سے پہلے کہ اسے معلوم ہو کہexecواقعی چلا بھی یا نہیں۔ binary path میں typo کی وجہ سے start job کامیاب ہو جاتی ہے، اور پھرMain process exited, code=exited, status=203/EXECکچھ ہی دیر بعد۔Type=exec،simpleکی طرح کام کرتا ہے، لیکن start job اس وقت تک انتظار کرتی ہے جب تکexecکامیاب نہ ہو جائے۔ اس طرح اوپر والا typo واضح start failure بن جاتا ہے۔ اس کے لیے systemd 240 یا اس کے بعد کا ورژن درکار ہے، جو ہر supported distribution میں موجود ہے۔ اسےsimpleپر ترجیح دیں۔Type=forkingتوقع کرتا ہے کہExecStart=کا process background daemon کو fork کرے گا اور پھر exit ہو جائے گا۔ systemd parent کے exit ہونے کا انتظار کرتا ہے، پھر اصل daemon تلاش کرتا ہے۔ اسےPIDFile=دیں۔ اس کے بغیرGuessMainPID=(جو default طور پر فعال ہے) صرف اس وقت کام کرتا ہے جب cgroup میں بالکل ایک process باقی ہو۔ اگر دو processes باقی رہ جائیں توMainPID،0ہی رہتا ہے۔Type=notifyکا مطلب ہے کہ service،sd_notify(3)کو call کرتی ہے اور جب وہ traffic serve کر سکے توREADY=1بھیجتی ہے۔ یہ systemd کو track کرنے کے لیے مختلف process دینے کی خاطرMAINPID=بھی بھیج سکتی ہے۔NotifyAccess=کا defaultmainہے، اس لیے child کی طرف سے بھیجی گئی notification نظرانداز ہو جاتی ہے اور journal اس PID کا نام درج کرتا ہے جہاں سے وہ notification آئی تھی۔Type=oneshotمیں کوئی مستقل main process نہیں ہوتا۔ExecStart=مکمل ہوتے ہی unit inactive ہو جاتی ہے، الا یہ کہ آپRemainAfterExit=yesset کریں۔ یہاںRestart=alwaysاورRestart=on-successمسترد کر دیے جاتے ہیں، اور پیغامService has Restart= set to either always or on-success, which isn't allowed for Type=oneshot services. Refusing.دکھایا جاتا ہے۔on-failureسمیت دیگر values قبول کی جاتی ہیں۔
دو Type=forking errors یاد رکھنے کے قابل ہیں، کیونکہ دونوں ایسی unit چھوڑ سکتے ہیں جو کسی واضح وجہ کے بغیر خراب دکھائی دیتی ہے:
myapp.service: Can't open PID file /run/myapp.pid (yet?) after start: No such file or directory
myapp.service: New main PID 4711 does not belong to service, and PID file is not owned by root. Refusing.پہلی error کا مطلب ہے کہ daemon اپنی PID file کسی دوسری جگہ لکھتا ہے، یا اسے اس وقت کے بعد لکھتا ہے جب systemd اسے تلاش کر چکا ہوتا ہے۔ دوسری error کا مطلب ہے کہ PID file میں ایسی process کا نام ہے جو unit کے cgroup سے باہر ہے۔ systemd اسے adopt کرنے سے انکار کرتا ہے، کیونکہ writable PID file بصورت دیگر systemd کو machine پر موجود کسی بھی process کو signals بھیجنے کا ذریعہ بن سکتی ہے۔
ریپر اسکرپٹ اپنے child processes کے ختم ہونے کو کیوں چھپا دیتا ہے
یہ وہ ساخت ہے جو عنوان میں موجود سوال پیدا کرتی ہے۔
#!/bin/bash
/usr/local/bin/myapp-web &
/usr/local/bin/myapp-worker &
waitunit Type=simple ہے، اس لیے main process shell ہے۔ wait بغیر arguments کے صرف اس وقت واپس آتا ہے جب ہر child ختم ہو چکا ہو۔ worker کو kill کریں تو shell web process کے لیے انتظار کرتا رہتا ہے؛ اس لیے shell exit نہیں کرتا، MainPID exit نہیں کرتا، اور Restart= سے دوبارہ جانچ نہیں ہوتی۔ اب cgroup میں ایک process کم ہے، systemctl status مختصر tree دکھاتا ہے، اور unit اب بھی active (running) ہے۔ systemd اس tree میں ہونے والی تبدیلیوں کی نگرانی نہیں کرتا۔
اسی غلطی کی دوسری صورت زیادہ خاموش ہوتی ہے:
ExecStart=/bin/sh -c 'export APP_ENV=production; /usr/local/bin/myapp'main process shell ہے، myapp نہیں۔ systemctl stop پر systemd main process کو SIGTERM بھیجتا ہے، لیکن foreground child کا انتظار کرنے والا shell یہ signal آگے نہیں بھیجتا۔ stop میں مکمل TimeoutStopSec لگتا ہے، جو default طور پر 90 seconds ہے، اور نتیجہ یہ ہوتا ہے:
myapp.service: State 'stop-sigterm' timed out. Killing.
myapp.service: Killing process 4711 (myapp) with signal SIGKILL.حل exec ہے۔ exec /usr/local/bin/myapp لکھیں تو shell کی جگہ program لے لیتا ہے؛ اس طرح MainPID program ہوتا ہے اور signals اس تک پہنچتے ہیں۔ اس سے بہتر یہ ہے کہ shell حذف کریں اور unit میں Environment= یا EnvironmentFile= استعمال کریں۔ یاد رکھیں کہ یہ bug اس وقت چھپ جاتا ہے جب -c string میں صرف ایک command ہو، کیونکہ bash اور dash دونوں اس صورت کو براہِ راست exec میں بدل دیتے ہیں۔ string میں دوسری command شامل کریں تو shell آپ کے program کے سامنے برقرار رہتا ہے۔
اسے test VPS پر دو minutes میں دوبارہ بنائیں
اوپر والا wrapper /usr/local/bin/two-children.sh کے نام سے محفوظ کریں، chmod +x کے ذریعے اسے executable بنائیں، اور دونوں program paths کو sleep 3600 سے تبدیل کریں۔ Type=simple اور Restart=on-failure کے ذریعے ایک unit کو اس کی طرف point کریں، پھر systemctl daemon-reload چلائیں اور اسے start کریں۔ systemd-cgls --unit two-children.service چلائیں اور تین PIDs نوٹ کریں: shell اور اس کے دو children۔ ایک child کو sudo kill <pid> کے ذریعے kill کریں۔ unit دوبارہ check کریں۔ tree میں ایک process کم ہے، state اب بھی active (running) ہے، اور journal میں کوئی نیا پیغام نہیں ہے۔ اب اس کے بجائے sudo kill -9 <shell pid> چلائیں۔ unit fail ہو جاتی ہے، باقی child کو صاف کر دیا جاتا ہے کیونکہ KillMode=control-group default ہے، اور journal Scheduled restart job, restart counter is at 1. دکھاتا ہے۔
مکمل Restart= اصطلاحات، اور on-failure کب always سے بہتر ہے
Restart= کی سات ممکنہ values ہیں، اور ان کے درمیان بنیادی فرق یہ ہے کہ clean exit کس کو شمار کیا جاتا ہے۔ systemd exit code 0، SuccessExitStatus= میں درج ہر code، اور signals SIGHUP، SIGINT، SIGTERM اور SIGPIPE کو clean exit سمجھتا ہے۔ باقی ہر صورت، بشمول SIGKILL اور SIGSEGV، unclean ہے۔
nodefault ہے۔ unit خود کو کبھی restart نہیں کرتی۔ اسی لیےRestart=line کے بغیر unit پہلے crash پر بند ہو جاتی ہے اور بند ہی رہتی ہے۔on-successصرف clean exit کے بعد restart کرتی ہے۔on-failurenon-zero exit code، unclean signal، start یا stop timeout، یا watchdog expiry کے بعد restart کرتی ہے۔on-abnormalunclean signal، timeout یا watchdog expiry کے بعد restart کرتی ہے، لیکن عام non-zero exit code کے بعد نہیں۔on-abortصرف unclean signal کے بعد restart کرتی ہے، یعنی crash کے بعد۔on-watchdogصرف اس وقت restart کرتی ہے جبWatchdogSec=expire ہو۔alwaysاوپر بیان کردہ ہر صورت کے بعد restart کرتی ہے، جس میں status 0 کے ساتھ clean exit بھی شامل ہے۔
on-failure طویل مدت تک چلنے والے daemon کے لیے درست default ہے۔ یہ crash کے بعد سروس بحال کرتی ہے، لیکن دانستہ exit 0 کو نظرانداز کرتی ہے۔ always ایسے program کے لیے ہے جو اپنے اختیار سے باہر کی وجوہات کی بنا پر clean exit کرتا ہے، مثلاً ایسا tunnel client جو remote end کے disconnect ہونے پر 0 واپس کرتا ہے۔ always کی قیمت یہ ہے کہ یہ bugs چھپا دیتی ہے: کوئی service start ہو، خراب config file پڑھے، error log کرے اور 0 کے ساتھ exit ہو جائے، تو وہ ہمیشہ loop کرتی رہے گی، اور واحد علامت restart counter کا بڑھنا ہو گی۔
SuccessExitStatus= clean اور unclean کے درمیان حد تبدیل کرتا ہے۔ Borg warnings کے لیے 1 اور errors کے لیے 2 کے ساتھ exit کرتا ہے، اس لیے SuccessExitStatus=1 کے بغیر backup unit ہر بار failed قرار پاتی ہے جب وہ کوئی unreadable file skip کرتی ہے۔ RestartPreventExitStatus= ان codes کی فہرست دیتا ہے جو always کے تحت بھی restart کو روکتے ہیں۔ یہ program کی طرف سے یہ بتانے کا درست طریقہ ہے کہ اسے دوبارہ start نہیں کیا جانا چاہیے۔ RestartForceExitStatus= اس کے برعکس کام کرتا ہے۔ Backup job کو restart loop کے بجائے timer کے ذریعے چلنے والی Type=oneshot unit میں رکھیں، اور وہ service اور timer pair جو job کو schedule کے مطابق چلاتا ہے اسی configuration کا نمونہ ہے۔
Testing کے بارے میں ایک تنبیہ۔ اپنی service کو عام kill <pid> سے kill کرنے پر SIGTERM بھیجا جاتا ہے، جو clean list میں شامل ہے۔ اس لیے Restart=on-failure درست طور پر کچھ نہیں کرے گا، اور آپ سمجھیں گے کہ configuration خراب ہے۔ اس کے بجائے kill -9 <pid> یا systemctl kill -s SIGKILL myapp.service استعمال کریں۔ یہ بھی یاد رکھیں کہ Restart= کی کوئی بھی value systemctl stop کے بعد، یا اس وقت لاگو نہیں ہوتی جب unit کو اس لیے stop کیا گیا ہو کہ BindsTo= یا PartOf= dependency ختم ہو گئی تھی۔ Stop job failure نہیں ہوتا۔
RestartSec، اور 100 millisecond کی default قدر
RestartSec= unit کے رکنے اور systemd کے اسے دوبارہ شروع کرنے کے درمیان وقفہ ہے، اور اس کی default قدر 100 milliseconds ہے۔ دیکھیں کہ آپ کی unit نے حقیقت میں کیا load کیا ہے:
systemctl show -p RestartUSec -p StartLimitIntervalUSec -p StartLimitBurst myapp.serviceجس unit نے یہ قدر set نہ کی ہو، اس میں RestartUSec=100ms ظاہر ہوتا ہے۔ یہ default اس service کے لیے مناسب ہے جو ایک بار crash ہونے کے بعد دوبارہ چل جائے۔ لیکن اس service کے لیے یہ غلط ہے جو بالکل start نہیں ہو سکتی، کیونکہ پانچ restarts آدھے second کے اندر ہو جاتے ہیں۔ یہی عمل اگلے حصے میں بیان کردہ rate limit کو trigger کرتا ہے۔ جو service database، mount یا network route کا انتظار کرتی ہو، اس کے لیے RestartSec=5s یا اس سے زیادہ قدر set کریں۔
August 2026 تک، systemd 254 اور اس کے بعد کے versions میں RestartSteps= اور RestartMaxDelaySec= بھی دستیاب ہیں۔ یہ متعدد attempts کے دوران delay کو RestartSec= سے بڑھا کر ایک مقررہ maximum تک لے جاتے ہیں۔ Ubuntu 24.04 میں systemd 255 شامل ہے اور یہ options دستیاب ہیں۔ Debian 12 میں systemd 252 شامل ہے، اس لیے یہ options دستیاب نہیں ہیں۔ جب dependency طویل وقت تک unavailable رہ سکتی ہو تو بڑھتا ہوا delay درست حل ہے۔
start request repeated too quickly کا حقیقی مطلب
یہ وہ حالت ہے جس میں صارفین سمجھتے ہیں کہ systemd نے من مانے انداز میں کوشش ترک کر دی۔ دراصل یہ ایک counter ہے۔ اصول یہ ہے: اگر کسی unit کو StartLimitIntervalSec= کے اندر StartLimitBurst= سے زیادہ مرتبہ start کیا جائے تو systemd اسے دوبارہ start کرنے سے انکار کر دیتا ہے اور اسے failed state میں رکھتا ہے۔ ڈیفالٹ 10 seconds میں 5 starts ہے۔
journal میں یہ سلسلہ دکھائی دیتا ہے:
myapp.service: Scheduled restart job, restart counter is at 5.
myapp.service: Start request repeated too quickly.
myapp.service: Failed with result 'start-limit-hit'.
Failed to start myapp.service - My application.اور systemctl start میں اس کا حل پہلے ہی درج ہوتا ہے:
Job for myapp.service failed because start of the service was attempted too often. See "systemctl status myapp.service" and "journalctl -xeu myapp.service" for details. To force a start use "systemctl reset-failed myapp.service" followed by "systemctl start myapp.service" again.systemctl reset-failed myapp.service counter اور failed state دونوں صاف کرتا ہے۔ کوئی اور چیز یہ کام نہیں کرتی، اس لیے سادہ systemctl start اس وقت تک مسترد ہوتا رہتا ہے جب تک آپ اسے نہ چلائیں۔ Manual starts بھی limit میں شمار ہوتے ہیں، اس لیے configuration file میں ترمیم کرتے وقت systemctl restart کی چند بے صبری سے کی گئی runs، کسی crash کے بغیر بھی، یہ limit فعال کر سکتی ہیں۔
گمراہ کرنے والی بات یہ ہے کہ start-limit-hit کبھی یہ نہیں بتاتا کہ service کیوں fail ہو رہی تھی۔ یہ صرف بتاتا ہے کہ service بار بار اور تیزی سے fail ہوئی۔ اصل وجہ اس سے اوپر موجود journal lines میں ہوتی ہے۔
دونوں settings [Unit] section میں شامل ہوتی ہیں۔ آپ کو ایسی مثالیں ملیں گی جن میں انہیں [Service] میں رکھا گیا ہے۔ پرانا systemd اسے قبول کرتا تھا، اور الجھن یہیں سے شروع ہوتی ہے۔ انہیں [Unit] میں لکھیں، پھر systemctl show سے systemd سے معلوم کریں کہ اس نے کیا load کیا ہے، کیونکہ صرف loaded value ہی مؤثر ہوتی ہے۔
[Unit]
Description=My application
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=exec
ExecStart=/usr/local/bin/myapp
Restart=on-failure
RestartSec=10sاس سے unit کو 5 minute کی مدت میں 5 attempts ملتی ہیں، پھر یہ کوشش ترک کر دیتا ہے۔ StartLimitIntervalSec=0 limit کو مکمل طور پر بند کر دیتا ہے۔ آپ کو اس انتخاب کے نتیجے کا علم ہونا چاہیے: جو service کبھی start نہیں ہو سکتی، وہ اب ہمیشہ retry کرتی رہے گی اور ہر مرتبہ journal میں entry لکھے گی۔ پورے machine کے ڈیفالٹس /etc/systemd/system.conf میں DefaultStartLimitIntervalSec= اور DefaultStartLimitBurst= کے طور پر موجود ہوتے ہیں۔
قریب کی ایک setting کے بارے میں تنبیہ ضروری ہے۔ StartLimitAction= یہ طے کرتا ہے کہ limit پوری ہونے پر کیا ہو، اور یہ reboot، reboot-force اور poweroff سمیت متعدد values قبول کرتا ہے۔ ڈیفالٹ none ہے، جو unit کو fail کر دیتا ہے اور machine کو اسی حالت میں رہنے دیتا ہے۔ Remote VPS پر poweroff کا مطلب ایسی machine ہے جو provider کے console کو کھولنے تک بند رہتی ہے۔
اصلاح 1: ہر unit کے لیے ایک process
تقریباً ہر صورت میں یہی درست طریقہ ہے۔ اگر دو پروگرام چلانے ہوں تو دو units لکھیں۔ اس طرح ہر unit کے پاس حقیقی main process، حقیقی exit status اور اپنی restart policy ہوتی ہے۔ آپ کو الگ logs، الگ resource limits اور الگ restart counters بھی ملتے ہیں، جو رات کے 3 بجے درکار ہوتے ہیں۔
Units کے درمیان تعلق shell script میں نہیں بلکہ unit files میں بیان کریں۔
After=صرف startup کی ترتیب طے کرتا ہے۔ یہ failures کے بارے میں کچھ نہیں بتاتا۔Requires=دوسرے unit کو اسی کے ساتھ شروع کرتا ہے، اور اگر دوسرا unit صراحتاً stop کیا جائے تو اس unit کو بھی stop کر دیتا ہے۔BindsTo=،Requires=کے علاوہ وہ صورت بھی شامل کرتا ہے جو یہاں اہم ہے: دوسرا unit کسی بھی وجہ سے، بشمول crash، stop ہو تو یہ unit بھی stop ہو جاتا ہے۔ اسےAfter=کے ساتھ استعمال کریں، ورنہ ordering غیر متعین رہتی ہے۔PartOf=stop اور restart کو نچلی سطح کے units تک منتقل کرتا ہے، اس لیےsystemctl restart myapp.targetہر اس unit تک پہنچتا ہے جو اس کاPartOf=ہے۔Upholds=(systemd 249 اور اس کے بعد کے versions، یعنی Ubuntu 22.04 اور بعد کے versions) نامزد unit کو چلتا رکھتا ہے: اگر وہ stop ہو جائے تو systemd اسے دوبارہ start کر دیتا ہے۔ اس پر بھی باقی تمام units کی طرح start rate limit لاگو ہوتی ہے۔
ایسا worker جسے اپنے API server کے بغیر کبھی نہیں چلنا چاہیے، اور جسے API کے up ہونے تک systemd چلتا رکھے:
# /etc/systemd/system/myapp-api.service
[Unit]
Description=myapp API server
Wants=network-online.target
After=network-online.target
Upholds=myapp-worker.service
[Service]
Type=exec
User=myapp
ExecStart=/usr/local/bin/myapp serve
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target# /etc/systemd/system/myapp-worker.service
[Unit]
Description=myapp background worker
BindsTo=myapp-api.service
After=myapp-api.service
StartLimitIntervalSec=120
StartLimitBurst=5
[Service]
Type=exec
User=myapp
ExecStart=/usr/local/bin/myapp worker
Restart=on-failure
RestartSec=5sworker میں [Install] section نہیں ہے اور اسے کبھی دستی طور پر enable نہیں کیا جاتا۔ API unit اسے Upholds= کے ذریعے شامل کرتا ہے، اس لیے systemctl enable --now myapp-api.service ہی واحد command ہے جو آپ چلاتے ہیں۔ reload کریں اور دیکھیں کہ systemd نے دونوں units کے ساتھ کیا configuration بنائی ہے:
sudo systemctl daemon-reload
systemd-analyze verify /etc/systemd/system/myapp-worker.service
systemctl list-dependencies myapp-api.servicesystemd-analyze verify صاف file کی صورت میں بالکل کوئی output نہیں دیتا۔ کوئی بھی output مسئلہ ظاہر کرتا ہے۔ عموماً وجہ یہ ہوتی ہے کہ systemd اس section میں لکھی ہوئی key کو تسلیم نہیں کرتا، یا کسی ایسے unit پر dependency موجود ہے جو موجود نہیں ہے۔
درست کریں دو: Type=notify، تاکہ systemd کو صرف PID سے زیادہ معلومات ملیں
اگر پروگرام systemd notification protocol استعمال کرتا ہے تو اسے فعال کریں۔ `Type=notify کے ساتھ سروس systemd کو بتاتی ہے کہ وہ کب تیار ہے۔ اس سے ordering محض امید کے بجائے حقیقی ہو جاتی ہے۔ یہ MAINPID= بھی بھیج سکتی ہے، تاکہ systemd` کو launcher کے بجائے متعلقہ process کی نشاندہی ہو سکے۔
`WatchdogSec= وہ حصہ ہے جس کے لیے یہ کوشش قابلِ قدر ہے۔ اسے set کرنے پر سروس کو کم از کم اتنی بار WATCHDOG=1 کو sd_notify(3) کے ذریعے بھیجنا ہوگا۔ جب یہ messages رک جاتے ہیں تو systemd سروس کو SIGABRT کے ساتھ terminate کرتا ہے اور اسے failed mark کر دیتا ہے۔ اس صورت میں Restart=on-failure یا Restart=on-watchdog` اسے دوبارہ شروع کر دیتا ہے۔ کسی ایسے process کو restart کرنے کا یہ واحد built-in طریقہ ہے جو زندہ ہو لیکن stuck ہو۔ exit-status کی کوئی policy اس صورت حال کو کبھی نہیں پکڑ سکتی۔
[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/local/bin/myapp serve
WatchdogSec=30s
Restart=on-failure
RestartSec=5sWatchdog کے trigger ہونے پر journal میں پہلے `myapp.service: Watchdog timeout (limit 30s)! اور اس کے بعد kill کا اندراج ہوتا ہے۔ اگر اس کے بجائے unit activating (start) میں بیٹھی رہتی ہے اور TimeoutStartSec ختم ہو جاتا ہے تو READY=1 کبھی موصول نہیں ہوا۔ اس کی وجہ یہ ہو سکتی ہے کہ پروگرام اس protocol کو support نہیں کرتا، یا NotifyAccess=main` child process سے آنے والی notification کو reject کر رہا ہے۔ journal دونوں PIDs کے ساتھ یہ تفصیل درج کرتا ہے۔
ایسے software کے لیے جو HTTP health endpoint فراہم کرتا ہو لیکن `sd_notify support نہ کرتا ہو، دو قابلِ عمل راستے ہیں۔ ایک چھوٹی timer unit بنائیں جو endpoint کو probe کرے اور systemctl restart` چلائے۔ دوسرا راستہ یہ ہے کہ probing کا کام container runtime کو دے دیں۔ Compose healthchecks اور ان کا restart behaviour اسی مقصد کے لیے موجود ہیں۔
یونٹ کے اندر supervisor چلانے والا طریقہ، صرف اس وقت جب کوئی اور راستہ نہ ہو
کچھ software واقعی processes کے ایسے bundle کی صورت میں release ہوتا ہے جو ایسے launcher کے پیچھے چلتا ہے جسے آپ الگ نہیں کر سکتے۔ ایسی صورت میں آپ یونٹ کے اندر supervisor چلاتے ہیں اور اس کا نتیجہ قبول کرتے ہیں: systemd، supervisor کی نگرانی کرتا ہے؛ supervisor باقی سب کی نگرانی کرتا ہے؛ اور آپ کی restart policy اب دو files میں موجود ہوتی ہے۔
اس کی عام مثال container runtime ہے۔ docker compose یا podman unit عین یہی pattern ہے۔ اس میں ہر container کی restart policy Compose file میں بیان ہوتی ہے، جبکہ systemd unit صرف runtime کو چلتا رکھتی ہے۔ اگر آپ کا setup ایسا ہی ہے تو وہ unit جو boot کے وقت Compose stack شروع کرتی ہے عملی configuration دکھاتی ہے۔ اس میں یہ بھی بتایا گیا ہے کہ وہاں Type=oneshot کو RemainAfterExit=yes کے ساتھ استعمال کرنا عموماً درست کیوں ہوتا ہے۔
cgroup اب بھی آپ کے حق میں کام کرتا ہے۔ supervisor جو کچھ بھی start کرتا ہے، وہ unit کے cgroup کے اندر رہتا ہے۔ اس لیے MemoryMax=، CPUQuota= اور stop کے وقت ہونے والی cleanup اب بھی پوری process tree پر لاگو ہوتی ہے۔ صرف restart کا فیصلہ supervisor کے حوالے کیا جاتا ہے۔
آپ جو بھی supervisor منتخب کریں، outer unit پر Restart=always اور اس کے اندر aggressive restart policy بغیر سوچے نہ لگائیں۔ restart logic کی دو تہیں، جن میں سے ہر ایک کی اپنی backoff ہو، ایسی service پیدا کرتی ہیں جو کئی منٹ تک بار بار flap کرتی رہتی ہے، جبکہ journal یہ واضح نہیں کرتا کہ ایسا کیوں ہو رہا ہے۔
ExitType=cgroup کا مطلب یہ نہیں کہ "کوئی بھی process ختم ہو تو restart کریں"
ExitType= (systemd 250 اور اس کے بعد کے ورژنز میں، اس لیے Ubuntu 24.04 اور Debian 12 دونوں میں موجود ہے) وہ setting ہے جو لوگ اس مسئلے کی تلاش کے دوران دیکھتے ہیں، لیکن یہ نام کے تاثر کے برعکس کام کرتی ہے۔ Default، ExitType=main، کا مطلب ہے کہ main process کے exit ہوتے ہی service کو stopped سمجھا جاتا ہے۔ ExitType=cgroup کا مطلب ہے کہ cgroup میں موجود آخری process کے exit ہونے تک service کو running سمجھا جاتا ہے۔
اس لیے ExitType=cgroup کسی ایک process کے ختم ہونے پر unit کو کم حساس بناتا ہے، زیادہ حساس نہیں۔ یہ اس program کے لیے درست setting ہے جو اپنا اصل worker fork کرتا ہے اور PID file لکھے بغیر parent سے exit ہو جاتا ہے، جس کی وجہ سے Type=forking daemon تلاش نہیں کر پاتا۔ یہاں بیان کی گئی failure کے لیے یہ setting غلط ہے۔
ایسی کوئی Restart= value نہیں جو "cgroup میں کوئی بھی process ختم ہو تو unit کو restart کریں" کا مطلب دے۔ اگر آپ کو یہ رویہ چاہیے تو ہر unit میں صرف ایک process ہونا چاہیے۔ اگر program کو الگ نہیں کیا جا سکتا اور wrapper script آپ کے اختیار میں ہے تو اس مقصد کے قریب ترین طریقہ wait -n ہے، جو پہلے child کے exit ہوتے ہی واپس آ جاتا ہے:
#!/bin/bash
/usr/local/bin/myapp-web &
/usr/local/bin/myapp-worker &
wait -n
exit 1اب کسی بھی child کے ختم ہونے سے wrapper non-zero status کے ساتھ ختم ہو جائے گا، اس لیے Restart=on-failure عمل کرے گا۔ یہ ایک سمجھوتا ہے، مکمل حل نہیں۔ دونوں programs کے لیے پھر بھی ایک ہی restart counter اور ایک ہی log stream ہوگی، اور ناکام حصے کو الگ سے restart کرنے کا کوئی طریقہ نہیں ہوگا۔
اصل میں کیا ہوا، اس کا معائنہ کیسے کریں
چار commands، اسی ترتیب سے۔
systemctl status myapp.service
systemd-cgls --unit myapp.service
systemctl show -p MainPID -p NRestarts -p Result -p ExecMainStatus myapp.service
journalctl -u myapp.service -b -o short-precisesystemctl status ایک ہی screen پر state، main PID اور cgroup tree دکھاتا ہے۔ صحت مند unit میں Active: active (running) نظر آتا ہے اور Main PID: line میں متوقع process کا نام ہوتا ہے۔ اگر نیچے موجود tree میں ایسے processes شامل ہوں جنہیں آپ نہیں پہچانتے، یا وہ process موجود نہ ہو جس کی آپ توقع کر رہے ہیں، تو وجہ واضح ہو چکی ہے۔
systemd-cgls --unit یہی tree بغیر truncation کے دکھاتا ہے۔ جب کسی unit میں چند processes سے زیادہ ہوں تو یہ فرق اہم ہو جاتا ہے۔
systemctl show machine-readable facts فراہم کرتا ہے۔ NRestarts= restart counter ہے۔ اس سے فوراً معلوم ہو جاتا ہے کہ کوئی service چالیس بار restart ہوئی ہے یا boot کے بعد سے مسلسل چل رہی ہے۔ Result= آخری failure reason رکھتا ہے: exit-code، signal، timeout، oom-kill، watchdog یا start-limit-hit۔ ExecMainStatus= آخری main process کا raw exit status ہے۔
journal میں واقعات کی ترتیب محفوظ ہوتی ہے۔ ان تین lines کو تلاش کریں:
myapp.service: Main process exited, code=exited, status=1/FAILURE
myapp.service: Failed with result 'exit-code'.
myapp.service: Scheduled restart job, restart counter is at 1.code=exited, status=N کا مطلب ہے کہ program نے N واپس کرنے کا انتخاب کیا۔ اس لیے خرابی program یا اس کی configuration میں ہے۔ code=killed, signal=SEGV کا مطلب ہے کہ program crash ہو گیا۔ code=killed, signal=TERM کا مطلب عموماً یہ ہے کہ کسی دوسری چیز نے اسے stop کرنے کو کہا۔ یہ failure نہیں ہے اور Restart=on-failure کو trigger نہیں کرے گا۔ code=dumped کا مطلب ہے کہ program نے core file چھوڑی ہے۔ coredumpctl list آپ کو یہ file دکھائے گا، جب systemd-coredump installed ہو۔
ایک سے زیادہ machines پر NRestarts وہ number ہے جسے schedule کے مطابق collect کرنا چاہیے۔ جس unit کا counter ہر روز بڑھتا ہے، وہ ہر روز fail ہو رہی ہے، چاہے کسی نے یہ بات محسوس نہ کی ہو۔ جب servers کی تعداد دو یا تین سے زیادہ ہو جائے تو ہر server پر ایک command چلانے کا مستقل طریقہ اس اندازے کو report میں بدل دیتا ہے۔
FAQ
systemctl میری service کو active کیوں دکھاتا ہے جبکہ process ختم ہو چکا ہے؟
systemd ہر service unit کے لیے ایک process، یعنی main process، track کرتا ہے، اور Restart= صرف اسی process کا exit status پڑھتا ہے۔ Unit کے شروع کیے ہوئے باقی تمام processes اسی cgroup میں رہتے ہیں۔ Unit رکنے پر systemd ان processes کو ختم کر دیتا ہے، لیکن ان کے exit ہونے کی نگرانی نہیں کرتا۔ systemctl show -p MainPID myapp.service چلائیں اور اس کی تعداد کا systemd-cgls --unit myapp.service سے موازنہ کریں۔ اگر ختم ہونے والا process tree میں موجود ہو لیکن MainPID نہ ہو، تو systemd نے اپنی مقررہ design کے مطابق کام کیا ہے۔ درست طریقہ یہ ہے کہ ہر unit میں ایک process ہو، اور units کے درمیان تعلق BindsTo= اور Upholds= کے طور پر درج کیا جائے۔
"start request repeated too quickly" کا کیا مطلب ہے؟
اس کا مطلب ہے کہ unit کو StartLimitIntervalSec= کے اندر StartLimitBurst= سے زیادہ مرتبہ start کیا گیا۔ یہ قدر بطور default 10 seconds میں 5 starts ہے، اس لیے systemd نے مزید کوشش روک دی۔ یہ rate limit ہے اور یہ نہیں بتاتی کہ service کیوں fail ہو رہی تھی۔ اس سے اوپر موجود journal lines پڑھیں۔ systemctl reset-failed myapp.service سے state صاف کریں، پھر بنیادی failure درست کریں۔ اگر service کسی سست چیز کے شروع ہونے کا انتظار کرتی ہے تو RestartSec= بڑھائیں، کیونکہ 100 milliseconds کا default gap پانچوں attempts کو ایک second سے کم وقت میں ختم کر دیتا ہے۔
کیا مجھے Restart=always یا Restart=on-failure استعمال کرنا چاہیے؟
تقریباً ہر صورت میں on-failure استعمال کریں۔ یہ crash، non-zero exit، timeout اور watchdog trip کے بعد service restart کرتا ہے، لیکن دانستہ exit 0 کو نظرانداز کرتا ہے۔ always صرف اس وقت استعمال کریں جب program اپنے اختیار سے باہر کسی وجہ کی بنا پر cleanly exit کرے، مثلاً کوئی client اپنے peer کے disconnect ہونے پر 0 واپس کرے۔ always کا نقصان یہ ہے کہ broken config پڑھنے والی service، ایک error log کرنے کے بعد 0 پر exit ہو، تو وہ ہمیشہ loop کرتی رہے گی۔ اس کی واحد نمایاں علامت systemctl show میں NRestarts کا بڑھنا ہوگی۔
process کو دستی طور پر ختم کرنے سے restart کیوں trigger نہیں ہوتا؟
کیونکہ systemd SIGHUP، SIGINT، SIGTERM اور SIGPIPE کو clean exits شمار کرتا ہے، جبکہ عام kill <pid> SIGTERM بھیجتا ہے۔ Restart=on-failure کے تحت clean exit failure نہیں ہوتا، اس لیے کچھ restart نہیں ہوتا اور configuration بظاہر خراب لگتی ہے، حالانکہ وہ خراب نہیں ہوتی۔ kill -9 <pid> یا systemctl kill -s SIGKILL myapp.service سے test کریں۔ یہ unclean termination ہے اور restart policy trigger کرتی ہے۔ یہی اصول بتاتا ہے کہ systemctl stop آپ کی restart policy میں مداخلت کیوں نہیں کرتا۔
StartLimitIntervalSec اور StartLimitBurst کہاں درج کیے جاتے ہیں؟
انہیں [Unit] section میں درج کیا جاتا ہے۔ پرانے مواد اور systemd کے پرانے versions میں انہیں [Service] میں رکھا جاتا تھا، اس لیے نقل کیے گئے examples ایک دوسرے سے مختلف ہو سکتے ہیں۔ اندازہ نہ لگائیں کہ آپ کا version کس section کو تسلیم کرتا ہے۔ systemctl daemon-reload کے بعد systemctl show -p StartLimitBurst -p StartLimitIntervalUSec myapp.service سے systemd سے پوچھیں کہ اس نے کیا load کیا ہے، اور ان numbers کو حتمی حقیقت سمجھیں۔ systemd-analyze verify /etc/systemd/system/myapp.service ان keys کی نشاندہی کرتا ہے جنہیں systemd بالکل نہیں پہچانتا، اور file درست ہو تو کچھ بھی print نہیں کرتا۔