systemd Type=simple, forking, notify: योग्य पर्याय
unit active दिसत असूनही daemon बंद आहे? simple, exec, forking, oneshot आणि notify मधून योग्य Type= निवडा आणि खरा main PID शोधण्याची पद्धत समजा.
systemd प्रक्रिया बंद झाल्यावरही unit active का दाखवते
systemd सेवा unit active राहते, जोपर्यंत systemd ज्या एका प्रक्रियेला मुख्य प्रक्रिया मानते ती जिवंत असते. [Service] विभागातील Type= कोणती प्रक्रिया मुख्य प्रक्रिया आहे हे ठरवते. चुकीचे मूल्य निवडल्यास systemd shell wrapper किंवा अल्पकाळ चालणाऱ्या parent प्रक्रियेवर लक्ष ठेवते, तर तुम्हाला आवश्यक असलेला daemon त्याच unit मध्ये बंद होतो. systemd ला ज्या प्रक्रियेवर लक्ष ठेवण्यास सांगितले आहे, त्या प्रक्रियेबाबत unit योग्य स्थिती दाखवत असते.
येथे restart policy बदलल्याने मदत होणार नाही. मुख्य प्रक्रिया बंद झाल्यावर Restart= कार्य करते. त्यामुळे मुख्य PID (process identifier) अजूनही चालू असलेल्या प्रक्रियेचा असल्यास Restart=always कधीही कार्यान्वित होत नाही. प्रथम Type= दुरुस्त करा. मुख्य प्रक्रिया प्रत्यक्षात बंद झाल्यानंतर systemd काय करते, हा स्वतंत्र निर्णय आहे. त्याचे स्पष्टीकरण Restart= आणि RestartSec= साठीच्या मार्गदर्शकात दिले आहे.
Type= प्रत्यक्षात काय ठरवते
प्रत्येक Type= मूल्य एकाच वेळी दोन प्रश्नांची उत्तरे देते. systemd या unit ला कधी सुरू झाले असे मानू शकते, आणि मुख्य प्रक्रिया कोणती आहे.
पहिले उत्तर ordering नियंत्रित करते. After= मध्ये तुमच्या unit चे नाव देणारी unit, systemd तुमची unit सुरू झाल्याचे जाहीर करेपर्यंत थांबते. "started" असा अहवाल खूप लवकर देणारे Type= dependent units ना तुमची सेवा प्रतिसाद देण्यापूर्वी सुरू होऊ देते.
दुसरे उत्तर supervision नियंत्रित करते. unit ने सुरू केलेली प्रत्येक प्रक्रिया systemd एका cgroup (control group) मध्ये ठेवते. ही kernel मधील सुविधा प्रक्रिया एकत्र गटबद्ध करते, त्यामुळे त्यांच्यावर एकत्र मर्यादा घालता येतात आणि त्या एकत्र बंद करता येतात. systemctl stop cleanup करण्यासाठी cgroup वापरते: KillMode= चे default मूल्य control-group असते, त्यामुळे unit थांबवताना तिच्यामधील प्रत्येक प्रक्रियेला signal पाठवला जातो. मुख्य PID ची व्याप्ती यापेक्षा कमी असते. तिचे exit unit संपवते आणि तिचा exit status unit चा result ठरवतो. cgroup ला मुख्य PID समजून वाचल्यावरच हा गोंधळ सुरू होतो.
Type=simple सुरू होण्याची नोंद बायनरी चालण्यापूर्वीच करतो
Type=simple हे default असते, जेव्हा ExecStart= सेट केलेले असते आणि Type= किंवा BusName= यांपैकी कोणतेही उपस्थित नसते. systemd process तयार करते, unit लगेच सुरू झाल्याचे मानते आणि त्या process ला main PID मानते. सेवा बायनरी execute होण्यापूर्वीच पुढील units सुरू होतात.
या शेवटच्या तपशीलामुळे एक सामान्य आश्चर्य स्पष्ट होते. ExecStart= path मध्ये टायपो असला तरी start job यशस्वी झाल्याचे दिसते. execution अयशस्वी झाल्यावर क्षणभराने failure आढळतो. systemd ही स्थिती exit code 203 सह नोंदवते. त्याच्या स्वतःच्या तक्त्यात याला EXEC असे नाव दिले आहे आणि सेवा बायनरी execute करण्यात अपयश अशी त्याची व्याख्या केली आहे. त्यामुळे systemctl start error न देता परतले, यावरून तुमची बायनरी अस्तित्वात आहे हे सिद्ध होत नाही.
foreground मध्ये राहणाऱ्या आणि स्वतःला background मध्ये न हलवणाऱ्या program साठी simple वापरा. बहुतांश आधुनिक daemons आणि तुम्ही स्वतः लिहिलेल्या जवळपास सर्व programs साठी हे लागू होते.
Type=exec प्रोग्राम प्रत्यक्षपणे सुरू होईपर्यंत प्रतीक्षा करते
Type=exec हे simple सारखेच आहे, पण त्यात आणखी एक टप्पा असतो. fork आणि binary ची execution या दोन्ही प्रक्रिया यशस्वी झाल्यानंतरच systemd unit सुरू झाली असे मानते. binary उपलब्ध नसणे किंवा resolve न होणारे User= आढळणे यामुळे आता start job स्वतःच अपयशी ठरते. याउलट, आधी यशस्वी झाल्याचे दाखवून क्षणभराने शांतपणे अपयशी होण्याची शक्यता राहत नाही.
Type=exec systemd 240 मध्ये आले. त्यामुळे सध्याच्या प्रत्येक server distribution मध्ये ते उपलब्ध आहे. August 2026 पर्यंत Ubuntu 24.04 मध्ये systemd 255 आणि Debian 13 मध्ये systemd 257 समाविष्ट आहे. तुमची आवृत्ती systemctl --version ने तपासा.
यासाठी सुरू होताना आणखी एक synchronisation step लागतो. त्याचा फायदा म्हणजे systemctl start कडून अचूक exit status मिळतो. foreground program साठी simple ऐवजी exec वापरा.
Type=forking आणि main PID कसा हरवतो
Type=forking systemd ला सांगते की ExecStart= मधील process child fork करून जाणूनबुजून exit करेल. systemd त्या पहिल्या process च्या exit होण्याची प्रतीक्षा करते आणि त्यानंतरच unit सुरू झाल्याचे मानते. मागे राहिलेला child हा daemon असतो. ही पद्धत SysV युगापासून चालत आली आहे. त्या काळात init script परतल्यानंतर daemon चे supervision करण्यासाठी काहीही उपलब्ध नव्हते आणि काय चालू आहे याची एकमेव नोंद PID file असायची. ही मर्यादा systemd ने init scripts ची जागा का घेतली याच्या केंद्रस्थानी आहे.
अडचण process ची ओळख निश्चित करण्यात आहे. systemd ने सुरू केलेला process संपलेला असल्यामुळे, उरलेल्या process पैकी मुख्य process कोणता आहे हे systemd ला ठरवावे लागते. PIDFile= मध्ये daemon लिहित असलेली file द्या. ही file साधारणपणे /run अंतर्गत असलेल्या path वर असते. त्यानंतर systemd त्या file मधून PID वाचते. त्या file मधील PID या service शी आधीपासून संबंधित process कडे निर्देश करतो का हेही systemd तपासते. त्यामुळे असंबंधित process चे नाव असलेली stale file थेट स्वीकारली जात नाही.
PIDFile= नसल्यास GuessMainPID= लागू होते आणि त्याची default value yes असते. Service एकाच process मध्ये स्थिरावल्यासच हा अंदाज विश्वसनीय असतो. Manual मध्ये ही मर्यादा स्पष्टपणे दिली आहे: daemon मध्ये एकापेक्षा जास्त process असतील, तर अंदाज चुकीचा ठरू शकतो आणि failure detection काम करणे थांबवते. Unit चा main PID 0 देखील होऊ शकतो. याचा अर्थ systemd कडे supervise करण्यासाठी कोणताही process उरत नाही.
Fork करणाऱ्या बहुतेक daemons मध्ये त्यांना foreground मध्ये ठेवणारा switch देखील असतो. तो switch Type=exec सोबत वापरा आणि PIDFile= line delete करा. घटकांची संख्या कमी असल्यास PID हरवण्याचे मार्गही कमी होतात.
काम पूर्ण होऊन बाहेर पडणाऱ्या कामासाठी Type=oneshot
Type=oneshot प्रक्रियेने चालू होऊन बाहेर पडणे अपेक्षित असते. प्रक्रिया बाहेर पडल्यानंतरच systemd युनिट सुरू झाल्याचे मानतो. त्यामुळे दुसऱ्या युनिटने प्रतीक्षा करणे आवश्यक असलेल्या कोणत्याही कामासाठी oneshot योग्य प्रकार आहे. युनिटमध्ये Type= किंवा ExecStart= यापैकी कोणतेही निर्दिष्ट केलेले नसल्यास, हाच प्रकार गृहीत धरला जातो.
oneshot साठी दोन वर्तन वैशिष्ट्यपूर्ण आहेत. एकापेक्षा अधिक ExecStart= ओळी स्वीकारणारा हा एकमेव प्रकार आहे आणि त्या ओळी क्रमाने चालतात. याचा start timeout देखील डीफॉल्टनुसार अक्षम असतो. त्यामुळे अडकलेला oneshot अनिश्चित काळ प्रतीक्षा करतो, जोपर्यंत तुम्ही स्वतः TimeoutStartSec= सेट करत नाही.
प्रक्रिया बाहेर पडल्यानंतर युनिट inactive स्थितीत परत जाते. RemainAfterExit=yes कोणतीही प्रक्रिया चालू नसतानाही त्याला active ठेवते. या पानाच्या सुरुवातीला दाखवलेल्या लक्षणाची ही जाणीवपूर्वक केलेली आवृत्ती आहे. युनिटचे काम एखादी स्थिती निर्माण करून ठेवणे असेल आणि एखादी प्रक्रिया चालू ठेवणे नसेल, तेव्हा हे योग्य असते. उदाहरणार्थ, firewall ruleset लोड करणे किंवा container stack सुरू करणे. रीबूटनंतर पुन्हा उपलब्ध होणाऱ्या Docker Compose stack मागील पद्धत हीच आहे. युनिट compose command चालवते, बाहेर पडते आणि त्याने सुरू केलेले containers युनिटपेक्षा जास्त काळ चालू राहत असल्यामुळे active राहते. वेळापत्रकाद्वारे सुरू केले जाणारे काम देखील oneshot युनिट वापरते. हा cron ऐवजी systemd timer वर job चालवण्याचा दुसरा भाग आहे.
Type=notify सेवा तयार झाल्याची माहिती स्वतः देऊ देते
Type=notify निर्णय सेवा स्वतः घेईल अशी व्यवस्था करते. प्रक्रिया NOTIFY_SOCKET environment variable मध्ये मिळालेल्या Unix socket च्या path वरून READY=1 पाठवेपर्यंत systemd start job उघडे ठेवते. C interface म्हणजे sd_notify(3), आणि अनेक servers ते आधीपासून support करतात.
"ती सुरू झाली आहे का" या प्रश्नाचे हे अचूक उत्तर आहे. simple आणि exec सेवा configuration वाचण्यापूर्वी किंवा listening socket उघडण्यापूर्वीच started स्थिती कळवतात. त्यामुळे dependent unit खूप लवकर सुरू होऊ शकते आणि तिचे पहिले connection fail होऊ शकते. notify सेवा स्वतः तयार असल्याचे सांगते त्याच क्षणी started स्थिती कळवते.
systemd हा message फक्त main process कडून स्वीकारते. NotifyAccess=main याचाच अर्थ आहे आणि Type=notify हे सूचित करते. Message child किंवा helper कडून येत असल्यास NotifyAccess=all सेट करा. Shell script systemd-notify --ready call करू शकते; परंतु तो स्वतंत्र, अल्पकाळ चालणारा process म्हणून execute होतो. त्यामुळे त्यासाठी NotifyAccess=all आवश्यक आहे आणि message पाठवणारा process आधीच exit झाला असल्यास systemd ला तो message कोणाकडून आला हे निश्चित करता येणार नाही. Protocol स्वतः implement करणारी सेवा अधिक विश्वसनीय असते.
यासंबंधीच्या आणखी दोन settings माहिती असणे उपयुक्त आहे. systemd 253 पासून उपलब्ध असलेले Type=notify-reload हेच handshake reloads साठीही लागू करते. त्यामुळे systemctl reload signal पाठवल्यानंतर लगेच return न होता सेवा reload पूर्ण झाल्याचे कळवते तेव्हा return होते. WatchdogSec= notifying service ला ठरावीक interval ने keep-alive message पाठवण्यास सांगते. Deadline चुकल्यास systemd ते failure मानते.
Type=dbus आणि Type=idle
Type=dbus सेवा D-Bus वर नाव नोंदवते तोपर्यंत प्रतीक्षा करते. D-Bus हा system आणि desktop सेवा परस्परांशी संवाद साधण्यासाठी वापरत असलेला message bus आहे. यासाठी BusName= आवश्यक आहे. BusName= सेट केल्यावर ते default होते. प्रत्यक्षात bus name नोंदवणाऱ्या सेवेसाठीच याचा वापर करा.
Type=idle हे simple प्रमाणे कार्य करते. मात्र queued jobs dispatch होईपर्यंत program चालवण्यास विलंब करते. हा विलंब जास्तीत जास्त five seconds असतो. Boot वेळी console output आणि status messages एकमेकांत मिसळू नयेत म्हणून हे उपलब्ध आहे. हे ordering tool नाही. त्यामुळे सामान्य service मध्ये याचा वापर करू नका.
रॅपर स्क्रिप्टमुळे systemd चुकीच्या PID वर का अडकते
मूळ समस्या निर्माण करणारी रचना अशी आहे.
[Service]
Type=simple
ExecStart=/opt/app/run.sh#!/bin/bash
export APP_ENV=production
/opt/app/bin/server --config /etc/app.yaml &
/opt/app/bin/exporter --port 9101systemd shell ला मुख्य PID म्हणून नोंदवते. exporter foreground मध्ये चालू असताना shell जिवंत राहते. server बंद पडल्यास shell ला त्याची जाणीव होत नाही. त्यामुळे मुख्य PID जिवंतच राहतो, unit active स्थितीतच राहते आणि Restart= कडे कारवाई करण्यासाठी काहीच राहत नाही. दोन्ही प्रक्रिया संपूर्ण वेळ unit च्या cgroup मध्ये असतात. त्यामुळे systemctl stop अजूनही cleanup योग्य प्रकारे करते. बिघडलेले supervision आहे; cleanup नाही.
दुरुस्ती unit मध्ये प्रत्यक्षात किती दीर्घकाळ चालणाऱ्या प्रक्रिया आहेत यावर अवलंबून असते.
एकच प्रक्रिया असल्यास shell ऐवजी ती प्रक्रिया चालवा.
#!/bin/bash
export APP_ENV=production
exec /opt/app/bin/server --config /etc/app.yamlexec shell च्या जागी नमूद केलेला प्रोग्राम चालवते आणि तोच PID ठेवते. त्यामुळे systemd ने नोंदवलेला PID आता daemon चा असतो. त्याहून चांगला उपाय म्हणजे wrapper काढून टाकणे. Environment= आणि EnvironmentFile= variables पुरवतात, तर ExecStartPre= setup step पुरवते. त्यामुळे systemd daemon थेट सुरू करू शकते आणि त्याचा PID सुरुवातीपासूनच अचूकपणे ओळखू शकते.
दोन प्रक्रिया असल्यास एकच PID संपूर्ण unit चे प्रतिनिधित्व करू शकत नाही. त्या दोन स्वतंत्र units मध्ये विभाजित करा आणि After= व Wants= वापरून त्यांचा क्रम ठरवा. प्रत्येक प्रक्रियेसाठी एक unit ही systemd उत्तम प्रकारे supervise करू शकणारी रचना आहे. प्रत्येक प्रक्रियेला स्वतंत्र restart behaviour मिळवून देण्याचा हाच एकमेव मार्ग आहे.
ExitType=cgroup मध्ये काय बदलते
ExitType= systemd 250 मध्ये जोडण्यात आले. डीफॉल्ट मूल्य main आहे: मुख्य प्रक्रिया बाहेर पडल्यावर unit थांबलेली मानली जाते. ExitType=cgroup वापरल्यास, त्याच्या cgroup मधील कोणतीही प्रक्रिया जिवंत असेपर्यंत unit चालू मानली जाते.
[Service]
Type=simple
ExitType=cgroup
ExecStart=/opt/app/launcherयामुळे एक विशिष्ट समस्या सुटते. प्रत्यक्ष काम सुरू करून नंतर स्वतः बाहेर पडणारा launcher असल्यास, ExitType=main अंतर्गत systemd unit थांबलेली मानेल आणि उरलेल्या प्रक्रिया बंद करेल. ExitType=cgroup वापरल्यास unit संपूर्ण process group चा मागोवा घेते.
हे काय सोडवत नाही, हे स्पष्ट असणे आवश्यक आहे. ExitType=cgroup मुळे किमान एक प्रक्रिया जिवंत असेपर्यंत unit सक्रिय राहते. त्यामुळे दोन daemon धारण करणारी unit त्यांपैकी एक बंद झाल्यानंतरही सक्रिय राहते. यामुळे launcher ची समस्या सुटते. मात्र, एका unit चे अनेक स्वतंत्र प्रक्रियांचे supervisor मध्ये रूपांतर होत नाही. ExitType= हे Type=oneshot सोबत वापरता येत नाही.
संसाधनांचे accounting देखील cgroup मध्येच नोंदवले जाते. त्यामुळे MemoryMax= आणि CPUQuota= सारख्या मर्यादा unit ने सुरू केलेल्या प्रत्येक प्रक्रियेला लागू होतात; मुख्य PID विषयी Type= काय सांगते, यावर त्याचा परिणाम होत नाही. याच्या त्या भागाचे वर्णन systemd वापरून सेवेची memory आणि CPU मर्यादित करणे येथे आहे.
systemd प्रत्यक्षात कोणत्या प्रक्रियेवर लक्ष ठेवत आहे हे कसे शोधावे
तुम्ही डीबग करत असलेल्या unit वर ही प्रक्रिया क्रमाने करा. systemd ने काय लोड केले ते वाचा. त्यानंतर ते कशाचा मागोवा घेत आहे ते वाचा. शेवटी process table शी तुलना करा.
systemctl cat app.service
systemctl show -p Type,ExitType,GuessMainPID,PIDFile,MainPID,RemainAfterExit app.servicesystemctl cat unit file आणि त्याला लागू होणारे सर्व drop-in एकत्र दाखवते. त्यामुळे तुम्ही पूर्वी संपादित केलेली file नव्हे, तर systemd ने लोड केलेली configuration वाचत आहात. systemctl show प्रभावी values दाखवते. यात तुम्ही नोंदवून न ठेवलेली default values देखील असतात. पुढे जाण्यापूर्वी MainPID ची value नोंदवा.
systemd-cgls --unit=app.service
ps -o pid,ppid,stat,etime,args -p "$(systemctl show -p MainPID --value app.service)"systemd-cgls unit च्या cgroup मधील प्रत्येक process दाखवते. ps line systemd ज्या एकमेव process वर देखरेख ठेवते त्याचे वर्णन करते. दोन्ही एकत्र वाचा. MainPID ची value 0 असल्यास systemd कडे लक्ष ठेवण्यासाठी कोणतीही process नाही. cgroup मध्ये तुमचा daemon असतानाही MainPID shell कडे निर्देश करत असल्यास, वर वर्णन केलेले wrapper प्रकरण आहे. अपेक्षेपेक्षा जास्त processes असलेला cgroup असल्यास launcher किंवा forking daemon कार्यरत आहे.
systemctl status app.service
journalctl -u app.service -bsystemctl status state line आणि cgroup tree एकत्र दाखवते. त्यामुळे दोन्ही प्रश्नांची उत्तरे अनेकदा एकाच वेळी मिळतात. journalctl -u ला -b वापरून केवळ या boot पुरते मर्यादित केल्यास systemd ने त्या unit साठी नोंदवलेल्या start आणि stop events दिसतात. त्यात systemd ने पाहिलेले exit codes देखील असतात. daemon स्वतःच्या log file मध्ये लिहित असल्यास ती file देखील वाचा. कारण systemd पर्यंत पोहोचलेली माहितीच ते नोंदवू शकते.
तुम्ही Type= मध्ये बदल केल्यास reload आणि restart करा.
systemd-analyze verify /etc/systemd/system/app.service
sudo systemctl daemon-reload
sudo systemctl restart app.servicesystemd-analyze verify file चे parsing करते आणि स्वीकारता न येणाऱ्या settings नोंदवते. daemon-reload मुळे systemd disk वरील unit files पुन्हा वाचते. बदललेली Type= आधीपासून चालू असलेल्या unit ला लागू होत नाही. त्यामुळे restart आवश्यक आहे; तो ऐच्छिक नाही.
त्यानंतर बदलाची चाचणी करा. तुम्हाला प्रत्यक्ष महत्त्वाची असलेली process systemd-cgls मधून मिळालेल्या PID ने शोधा आणि ती kill करा. लगेच systemctl is-active app.service चालवा. Type= योग्य असल्यास unit active state मधून बाहेर पडते. ती active राहिल्यास systemd अजूनही दुसऱ्या कशावर तरी लक्ष ठेवत आहे.
तुम्ही कोणता systemd service Type= वापरावा
- foreground मध्ये चालू राहणाऱ्या प्रोग्रामसाठी:
Type=exec. - readiness notification समर्थित करणाऱ्या प्रोग्रामसाठी:
Type=notify; reload पूर्ण झाल्याची पुष्टीही तो करत असल्यासnotify-reload. - background मध्ये जाण्याचा आग्रह धरणाऱ्या daemon साठी:
Type=forkingसोबतPIDFile=, किंवा त्याचा foreground switch वापरूनType=exec. - काम करून बाहेर पडणाऱ्या script साठी:
Type=oneshot; state मागे ठेवणे हा उद्देश असल्यासRemainAfterExit=yesदेखील. - children चालू ठेवून स्वतः बाहेर पडणाऱ्या launcher साठी:
Type=simpleसोबतExitType=cgroup.
तृतीय-पक्ष daemon साठी कोणता प्रकार आवश्यक आहे याबद्दल खात्री नसल्यास, आधी त्याची packaged unit file वाचा. distribution ने पुरवलेल्या unit वर systemctl cat चालवल्यास upstream ने निवडलेले Type= दिसते. ही निवड तुमच्या निवडीपेक्षा अधिक लोकांनी तपासलेली असते.
FAQ
माझे systemd unit प्रक्रिया बंद झाल्यानंतरही active का राहते?
कारण systemd मुख्य प्रक्रिया म्हणून ज्या प्रक्रियेला मानते ती अजूनही चालू असते. systemd प्रत्येक process वर लक्ष ठेवत नाही. ते Type= नुसार निवडलेल्या प्रत्येक सेवेसाठी एका PID वर लक्ष ठेवते. Type=simple वापरून सुरू केलेली wrapper script हे याचे नेहमीचे कारण आहे. त्यामुळे shell हा main PID ठरतो आणि shell ने background मध्ये सुरू केलेला daemon बंद झाला तरी unit active राहते. systemctl show -p MainPID app.service चालवा. त्यानंतर systemd-cgls --unit=app.service वापरून unit चे cgroup सूचीबद्ध करा आणि दोन्हींची तुलना करा.
Type=simple आणि Type=exec यांच्यात काय फरक आहे?
Type=simple मध्ये systemd ने process तयार करताच unit सुरू झाले असे मानले जाते. त्या वेळी binary execute झालेली नसते. त्यामुळे ExecStart= मधील चुकीचा path असला तरी start job यशस्वी झाल्याचे दिसते आणि त्यानंतर failure येतो. Type=exec मध्ये execution यशस्वी होईपर्यंत systemd प्रतीक्षा करते. त्यामुळे failure स्वतः start job कडून नोंदवला जातो. दोन्ही प्रकारांत तीच process main PID म्हणून मानली जाते. Type=exec साठी systemd 240 किंवा त्यानंतरची आवृत्ती आवश्यक आहे.
Type=forking सह PIDFile= अजूनही आवश्यक आहे का?
होय, daemon PIDFile लिहित असल्यास ते आवश्यक आहे. ते नसल्यास systemd GuessMainPID= वर अवलंबून राहते. हा अंदाज असतो आणि एकाच process मध्ये स्थिरावणाऱ्या सेवेसाठीच तो विश्वासार्ह असतो. अंदाज चुकीचा ठरल्यास किंवा लावता न आल्यास त्या unit साठी failure detection आणि automatic restarting काम करणे थांबवतात. PIDFile= ला daemon ज्या अचूक path वर PIDFile लिहितो त्या path कडे निर्देशित करा. हा path सामान्यतः /run अंतर्गत असतो.
RemainAfterExit=yes कधी वापरावे?
जेव्हा unit चा उद्देश process चालू ठेवणे नसून system state बदलणे असतो. firewall rules लोड करणारे किंवा container stack सुरू करणारे Type=oneshot unit काम पूर्ण होताच exit होते. RemainAfterExit=yes नसल्यास unit inactive होते. त्यामुळे systemctl stop कडे stop करण्यासाठी काहीही उरत नाही आणि ExecStop= cleanup चालवण्याचीही पद्धत राहत नाही. RemainAfterExit=yes वापरल्यास कोणतीही process नसतानाही unit active राहते. या परिस्थितीत हेच अपेक्षित असते.
Type= बदलण्यासाठी daemon-reload आवश्यक आहे का?
होय. Unit restart करणेही आवश्यक आहे. systemctl daemon-reload मुळे systemd disk वरील unit files पुन्हा वाचते. मात्र चालू instance सुरू होताना वापरलेले Type= कायम ठेवते. चाचणी करण्यापूर्वी sudo systemctl daemon-reload आणि त्यानंतर sudo systemctl restart app.service चालवा. अन्यथा तुम्ही अजूनही जुने supervision behaviour पाहत असाल.