systemd ஏன் service-ஐ restart செய்யவில்லை?
Restart= கட்டளை முதன்மை process-ஐ மட்டுமே கண்காணிக்கும். cgroup-ல் உள்ள மற்ற process-கள் செயலிழந்தால் systemd அதை அறியாது. Type= மற்றும் restart வரம்புகள் எவ்வாறு செயல்படுகின்றன என்பதை
சுருக்கமான பதில்: systemd restart கொள்கைகள் ஒரு process-ஐ மட்டுமே கண்காணிக்கும்
systemd restart கொள்கைகள் ஒவ்வொரு unit-க்கும் ஒரு process-ஐ மட்டுமே கண்காணிக்கும்: அது முதன்மை process (main process) ஆகும். Restart= அந்த ஒரு process-ன் exit status-ஐ மட்டுமே வாசிக்கும், மற்றவற்றை அல்ல. ஒரு unit-ன் control group-ல் இருபது process-கள் இருக்கலாம்; அவற்றில் ஒன்று செயலிழந்தாலும், முதன்மை process தொடர்ந்து இயங்குவதால் அந்த unit active (running) நிலையிலேயே இருக்கும். systemd-ன் பார்வையில் எதுவும் தோல்வியடையவில்லை என்பதால், எதுவும் restart செய்யப்படாது.
systemd-க்கு மற்ற process-களைப் பற்றித் தெரியும். unit நிறுத்தப்படும்போது அது மற்ற process-களைக் கொல்லும், unit-ன் வரம்புகளுக்குள் அவற்றின் memory பயன்பாட்டைக் கணக்கிடும், unit-ன் CPU ஒதுக்கீட்டை அவற்றுக்குச் செயல்படுத்தும், மேலும் systemctl status-ல் அவற்றைப் பட்டியலிடும். ஆனால், அது அவற்றின் exit status-ஐ ஒருபோதும் வாசிப்பதில்லை. restart தர்க்கமும் (restart logic) cgroup-ம் இரண்டு வெவ்வேறு விஷயங்கள்; இந்த வழிகாட்டியின் பெரும்பகுதி அவற்றுக்கு இடையேயான இந்த இடைவெளியைப் பற்றியது.
cgroup எதைக் கொண்டுள்ளது மற்றும் restart logic எதைப் படிக்கிறது
cgroup (control group) என்பது செயல்முறைகளின் (processes) தொகுப்பைக் கொண்ட ஒரு kernel object ஆகும். ஒவ்வொரு service unit-க்கும் அதன் பெயரிலேயே ஒரு cgroup உருவாக்கப்படுகிறது. ஒரு செயல்முறை அதிலிருந்து வெளியேற முடியாது. குழந்தைகள் தங்கள் பெற்றோரின் cgroup-ஐப் பெறுகின்றன, மேலும் ஒரு unprivileged செயல்முறை தன்னைத்தானே வேறொரு இடத்திற்கு மாற்றிக்கொள்ள முடியாது. இதனால்தான் systemd-ஆல் இரண்டு முறை fork செய்யும் daemon-ஐயும் முழுமையாக நீக்க முடிகிறது; பழைய init scripts-ஆல் இதை நம்பகத்தன்மையுடன் செய்ய முடியவில்லை.
இந்த இரண்டு உண்மைகளையும் அருகருகே கவனியுங்கள்:
systemd-cgls --unit myapp.service
systemctl show -p MainPID -p NRestarts -p Restart -p RestartUSec myapp.servicesystemd-cgls என்பது unit-ல் உள்ள ஒவ்வொரு செயல்முறையையும் பட்டியலிடுகிறது. MainPID என்பது restart policy படிக்கும் ஒரே ஒரு எண் ஆகும். இவை இரண்டும் உங்கள் எதிர்பார்ப்பிற்கு மாறாக இருந்தால், அந்த முரண்பாடே பிழை (bug) ஆகும். MainPID=0 என்பது தவறான PID-ஐ விட மோசமானது: அதாவது systemd எதையும் கண்காணிக்கவில்லை என்று பொருள், எனவே எந்தவொரு Restart= மதிப்பும் செயல்படாது.
main-process விதியில் ஒரு முக்கிய விதிவிலக்கு உள்ளது. kernel-ன் out-of-memory killer, unit-ன் cgroup-க்குள் இருக்கும் ஏதேனும் ஒரு செயல்முறையைக் கொன்றால், systemd அதைக் கவனிக்கும், ஏனெனில் அது cgroup-ன் memory.events கோப்பைக் கண்காணிக்கிறது. OOMPolicy= அடுத்து என்ன நடக்க வேண்டும் என்பதைத் தீர்மானிக்கிறது, அதன் default மதிப்பு stop ஆகும்: முழு unit-ம் நிறுத்தப்படும், முடிவு oom-kill எனப் பதியப்படும், இது ஒரு தோல்வியாகக் கருதப்படும், எனவே Restart=on-failure செயல்படும். இது 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-ஐ நிறுத்திவிடும், ஆனால் அதே child segmentation fault காரணமாக இறந்தால் அது unit-ஐ நிறுத்தாது. நீங்கள் ஒரு unit-க்கு memory வரம்புகளை அமைத்தால், restart policy-ஐ மாற்றியமைக்கும் முன் MemoryMax மற்றும் CPUQuota ஆகியவை unit-ன் cgroup-க்கு எவ்வாறு பொருந்தும் என்பதைப் படிக்கவும், ஏனெனில் இந்த இரண்டு அம்சங்களும் இங்குதான் ஒன்றிணைகின்றன.
Type= முதன்மை process-ஐ எவ்வாறு தேர்வு செய்கிறது
Type= என்பது [Service] பிரிவில் தொடக்க வரிசைப்படுத்துதலை மட்டும் குறிப்பதல்ல. எந்த PID (process ID) MainPID ஆக மாறும் என்பதைத் தீர்மானிக்கும் விதியே இதுவாகும்; இதுவே Restart= எதைக் காண முடியும் என்பதையும் தீர்மானிக்கிறது.
Type=simpleஎன்பது இயல்புநிலை (default) ஆகும். systemd-ஆல்ExecStart=-லிருந்து fork செய்யப்படும் process-தான் முதன்மை process.execசரியாகச் செயல்படுகிறதா என்று தெரிவதற்கு முன்பே, அந்த unit தொடங்கிவிட்டதாக systemd குறித்துக்கொள்ளும். binary பாதையில் எழுத்துப் பிழை இருந்தால், தொடக்கப் பணி (start job) வெற்றிகரமாக முடிந்தது போலக் காட்டும், ஆனால் ஒரு கணம் கழித்துMain process exited, code=exited, status=203/EXECதோல்வியடையும்.Type=execஎன்பதுsimpleபோலவே செயல்படும், ஆனால்execவெற்றிகரமாக முடியும் வரை தொடக்கப் பணி காத்திருக்கும். இது மேலே குறிப்பிட்ட எழுத்துப் பிழையை ஒரு உண்மையான தொடக்கத் தோல்வியாக (start failure) மாற்றும். இதற்கு systemd 240 அல்லது அதற்குப் பிந்தைய பதிப்பு தேவை, இது தற்போது ஆதரிக்கப்படும் அனைத்து விநியோகங்களிலும் (distributions) உள்ளது.simple-க்கு பதிலாக இதையே பயன்படுத்தவும்.Type=forkingஎன்பதுExecStart=-லிருந்து வரும் process, ஒரு background daemon-ஐ உருவாக்கிவிட்டு வெளியேறும் என்று எதிர்பார்க்கிறது. parent process வெளியேறும் வரை systemd காத்திருந்து, பின் உண்மையான daemon-ஐத் தேடும். அதற்குPIDFile=-ஐ வழங்கவும். அது இல்லையென்றால்,GuessMainPID=(இயல்புநிலையில் உள்ளது) cgroup-ல் ஒரே ஒரு process இருக்கும்போது மட்டுமே செயல்படும். இரண்டு process-கள் இருந்தால்,MainPIDநிலையிலேயே0நீடிக்கும்.Type=notifyஎன்பது, அந்த servicesd_notify(3)-ஐ அழைத்து, போக்குவரத்தை (traffic) கையாளத் தயாரானதும்READY=1-ஐ அனுப்பும் என்று பொருள். systemd கண்காணிப்பதற்கென ஒரு தனி process-ஐ வழங்கMAINPID=-ஐயும் அது அனுப்பலாம்.NotifyAccess=இயல்புநிலையாகmain-ஆக இருப்பதால், ஒரு child அனுப்பும் அறிவிப்பு புறக்கணிக்கப்படும், மேலும் journal அந்த அறிவிப்பு வந்த PID-ஐக் குறிப்பிடும்.Type=oneshot-க்கு நிலையான முதன்மை process எதுவும் இல்லை.RemainAfterExit=yes-ஐ அமைக்காவிட்டால்,ExecStart=முடிந்தவுடன் அந்த unit செயலற்றதாகிவிடும்.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உள்ளிட்ட பிற மதிப்புகள் ஏற்றுக்கொள்ளப்படும்.
இரண்டு Type=forking பிழைகளை நினைவில் கொள்வது அவசியம், ஏனெனில் இவை ஒவ்வொன்றும் எந்தக் காரணமும் இன்றி பழுதடைந்தது போன்ற தோற்றத்தை 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.முதல் பிழை, daemon தனது PID கோப்பை வேறொரு இடத்தில் எழுதுகிறது அல்லது systemd தேடும் நேரத்தை விடத் தாமதமாக எழுதுகிறது என்று பொருள். இரண்டாவது பிழை, PID கோப்பில் உள்ள process அந்த unit-ன் cgroup-க்கு வெளியே உள்ளது என்று பொருள். இதை systemd ஏற்காது, ஏனெனில் எழுதக்கூடிய PID கோப்பு இருந்தால், systemd-ஐப் பயன்படுத்தி சர்வரில் உள்ள எந்தவொரு process-க்கும் சிக்னல்களை அனுப்பும் வாய்ப்பு உருவாகிவிடும்.
wrapper script ஏன் அதன் child process-களின் இறப்பை மறைக்கிறது
தலைப்பில் உள்ள கேள்விக்கு வழிவகுக்கும் அமைப்பு இதோ.
#!/bin/bash
/usr/local/bin/myapp-web &
/usr/local/bin/myapp-worker &
waitஇந்த unit Type=simple ஆக இருப்பதால், முதன்மை process ஒரு shell ஆகும். வாதங்கள் (arguments) ஏதுமின்றி wait பயன்படுத்தப்படும்போது, அனைத்து child process-களும் வெளியேறிய பின்னரே அது திரும்பும். worker process-ஐ kill செய்தாலும், shell தொடர்ந்து web process-க்காகக் காத்திருக்கும். இதனால் shell வெளியேறாது, எனவே MainPID வெளியேறாது, மேலும் Restart= ஒருபோதும் அழைக்கப்படாது. cgroup-ல் இப்போது ஒரு process குறைவாக இருக்கும், systemctl status சுருக்கப்பட்ட tree-ஐக் காட்டும், மேலும் unit இன்னும் active (running) நிலையிலேயே இருக்கும். அந்த tree-ல் ஏற்படும் மாற்றங்களை systemd கண்காணிப்பதில்லை.
இதே தவறின் இரண்டாவது வடிவம் இன்னும் அமைதியானது:
ExecStart=/bin/sh -c 'export APP_ENV=production; /usr/local/bin/myapp'இங்கே முதன்மை process shell ஆகும், myapp அல்ல. systemctl stop-ல், systemd முதன்மை process-க்கு SIGTERM-ஐ அனுப்பும், ஆனால் foreground-ல் உள்ள child-க்காகக் காத்திருக்கும் shell அந்த signal-ஐக் கடத்தாது. இதனால் stop செயல்முறை முழுமையாக TimeoutStopSec (இயல்பாக 90 வினாடிகள்) எடுத்துக்கொண்டு, பின்வருமாறு முடிவடையும்:
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-ஆகவே இருக்கும், மேலும் signal-கள் நேரடியாக அதைச் சென்றடையும். அதைவிடச் சிறந்தது, shell-ஐ நீக்கிவிட்டு unit-ல் Environment= அல்லது EnvironmentFile=-ஐப் பயன்படுத்துவதாகும். -c சரத்தில் ஒரே ஒரு command மட்டும் இருந்தால் இந்த bug மறைந்துவிடும் என்பதை கவனிக்கவும், ஏனெனில் bash மற்றும் dash ஆகிய இரண்டும் அந்தச் சூழலில் நேரடியாக exec-ஐச் செய்யும் வகையில் optimize செய்கின்றன. அந்தச் சரத்தில் இரண்டாவது command-ஐச் சேர்த்தால், shell உங்கள் program-க்கு முன்னால் தொடர்ந்து இயங்கிக்கொண்டே இருக்கும்.
ஒரு test VPS-ல் இரண்டு நிமிடங்களில் இதைச் செய்து பாருங்கள்
மேலே உள்ள wrapper-ஐ /usr/local/bin/two-children.sh எனச் சேமித்து, chmod +x மூலம் executable ஆக்கி, இரண்டு program path-களையும் sleep 3600 என மாற்றவும். Type=simple மற்றும் Restart=on-failure மூலம் ஒரு unit-ஐ உருவாக்கி, பின் systemctl daemon-reload செய்து அதைத் தொடங்கவும். systemd-cgls --unit two-children.service-ஐ இயக்கினால் மூன்று PID-களைக் காணலாம்: shell மற்றும் அதன் இரண்டு child-கள். ஒரு child-ஐ sudo kill <pid> மூலம் kill செய்யவும். unit-ஐ மீண்டும் சரிபார்க்கவும். tree-ல் ஒரு process குறைவாக இருக்கும், நிலை இன்னும் active (running) என்றே இருக்கும், மேலும் journal-ல் புதிய தகவல்கள் எதுவும் இருக்காது. இப்போது அதற்குப் பதிலாக sudo kill -9 <shell pid>-ஐ இயக்கவும். unit தோல்வியடையும், மீதமுள்ள child process நீக்கப்படும் (ஏனெனில் KillMode=control-group என்பது இயல்பான அமைப்பு), மேலும் journal-ல் Scheduled restart job, restart counter is at 1. என்று காட்டும்.
Restart= கட்டளைகளின் முழுமையான விளக்கம் மற்றும் on-failure எப்போது always-ஐ விடச் சிறந்தது
Restart= ஏழு மதிப்புகளில் ஒன்றை ஏற்கும். இதில் எது 'சுத்தமான' (clean) வெளியேற்றம் என்பதுதான் முக்கிய வேறுபாடு. systemd, exit code 0, SuccessExitStatus=-ல் பட்டியலிடப்பட்டுள்ள எந்தவொரு குறியீடு, மற்றும் SIGHUP, SIGINT, SIGTERM, SIGPIPE ஆகிய சிக்னல்களை சுத்தமான வெளியேற்றமாகக் கருதுகிறது. மற்ற அனைத்தும், SIGKILL மற்றும் SIGSEGV உட்பட, சுத்தமற்றவை (unclean).
noஎன்பது இயல்பான (default) அமைப்பாகும். இது தானாகவே restart ஆகாது. எனவே,Restart=வரி இல்லாத ஒரு unit, முதல்முறை செயலிழக்கும்போதே நின்றுவிடும்.on-successசுத்தமான வெளியேற்றத்திற்குப் பிறகு மட்டுமே restart ஆகும்.on-failureபூஜ்ஜியம் அல்லாத exit code, சுத்தமற்ற சிக்னல், start/stop timeout அல்லது watchdog காலாவதி ஏற்படும்போது restart ஆகும்.on-abnormalசுத்தமற்ற சிக்னல், timeout அல்லது watchdog காலாவதிக்கு மட்டுமே restart ஆகும்; சாதாரண பூஜ்ஜியம் அல்லாத exit code-க்கு restart ஆகாது.on-abortசுத்தமற்ற சிக்னலுக்கு, அதாவது ஒரு crash-க்கு மட்டுமே restart ஆகும்.on-watchdogWatchdogSec=காலாவதியாகும் போது மட்டுமே restart ஆகும்.alwaysமேலே உள்ள அனைத்துச் சூழல்களிலும், 0 என்ற சுத்தமான exit status உட்பட, restart ஆகும்.
நீண்ட நேரம் இயங்கும் daemon-களுக்கு on-failure சரியான default ஆகும். இது crash-ஐச் சரிசெய்து, திட்டமிட்ட exit 0-ஐ அப்படியே விட்டுவிடும். always என்பது, தனது கட்டுப்பாட்டில் இல்லாத காரணங்களால் சுத்தமாக வெளியேறும் நிரல்களுக்குப் பொருந்தும். உதாரணமாக, மறுமுனை துண்டிக்கப்படும்போது 0 எனத் திரும்பும் tunnel client. always-ன் ஆபத்து என்னவென்றால், இது பிழைகளை மறைத்துவிடும்: ஒரு service தொடங்கி, தவறான config கோப்பை வாசித்து, பிழையைப் பதிவு செய்துவிட்டு 0 என வெளியேறினால், அது முடிவில்லாமல் restart ஆகிக்கொண்டே இருக்கும். restart எண்ணிக்கை உயர்வது மட்டுமே இதன் அறிகுறியாக இருக்கும்.
SuccessExitStatus= சுத்தமான மற்றும் சுத்தமற்ற வெளியேற்றங்களுக்கு இடையிலான எல்லையை மாற்றுகிறது. Borg எச்சரிக்கைகளுக்கு 1 மற்றும் பிழைகளுக்கு 2 என வெளியேறும். எனவே, SuccessExitStatus=1 இல்லாத backup unit, படிக்க முடியாத ஒரு கோப்பைத் தவிர்க்கும்போதெல்லாம் failed எனக் காட்டப்படும். always-ன் கீழும் restart-ஐத் தடுக்கும் குறியீடுகளை RestartPreventExitStatus= பட்டியலிடுகிறது. ஒரு நிரல் மீண்டும் தொடங்கக்கூடாது என்று சொல்வதற்கான சுத்தமான வழி இது. RestartForceExitStatus= இதற்கு நேர்மாறாகச் செயல்படுகிறது. ஒரு backup பணியை restart loop-ல் வைப்பதற்குப் பதிலாக, Type=oneshot unit மற்றும் timer மூலம் இயக்குவதே சிறந்தது. ஒரு குறிப்பிட்ட கால அட்டவணையில் பணியை இயக்கும் service மற்றும் timer ஜோடி இதற்கான சரியான முறையாகும்.
சோதனை செய்யும்போது ஒரு எச்சரிக்கை: உங்கள் service-ஐ சாதாரண kill <pid> மூலம் நிறுத்தினால், அது SIGTERM-ஐ அனுப்பும். இது சுத்தமான பட்டியலில் உள்ளதால், Restart=on-failure சரியாகச் செயல்படாது; இதனால் உங்கள் config தவறானது என்று நீங்கள் தவறாக நினைக்கலாம். அதற்குப் பதிலாக kill -9 <pid> அல்லது systemctl kill -s SIGKILL myapp.service-ஐப் பயன்படுத்தவும். மேலும், systemctl stop-க்குப் பிறகோ அல்லது BindsTo= அல்லது PartOf= dependency நீக்கப்பட்டதால் unit நிறுத்தப்பட்டாலோ, Restart=-ன் எந்த மதிப்பும் இயங்காது என்பதை நினைவில் கொள்க. ஒரு stop job என்பது தோல்வி அல்ல.
RestartSec மற்றும் 100 மில்லி விநாடி இயல்புநிலை
RestartSec= என்பது ஒரு unit நின்ற பிறகு, systemd அதை மீண்டும் தொடங்குவதற்கு இடைப்பட்ட நேரமாகும். இதன் இயல்புநிலை 100 மில்லி விநாடிகள் ஆகும். உங்கள் unit உண்மையில் எதை ஏற்றுகிறது என்பதைச் சரிபார்க்கவும்:
systemctl show -p RestartUSec -p StartLimitIntervalUSec -p StartLimitBurst myapp.serviceஎந்த மதிப்பையும் அமைக்காத unit-ல் RestartUSec=100ms என்று காட்டும். ஒருமுறை செயலிழந்து மீண்டும் வரும் service-க்கு இந்த இயல்புநிலை போதுமானது. ஆனால், தொடங்குவதில் சிக்கல் உள்ள service-க்கு இது தவறானது. ஏனெனில், அரை விநாடிக்குள் ஐந்து முறை restart செய்ய முயற்சிக்கும்போது, அடுத்து விவரிக்கப்படும் rate limit சிக்கல் ஏற்படும். Database, mount அல்லது network route-க்காகக் காத்திருக்கும் எந்தவொரு service-க்கும் RestartSec=5s அல்லது அதற்கு மேற்பட்ட மதிப்பை அமைக்கவும்.
ஆகஸ்ட் 2026 நிலவரப்படி, systemd 254 மற்றும் அதற்குப் பிந்தைய பதிப்புகளில் RestartSteps= மற்றும் RestartMaxDelaySec= வசதிகள் உள்ளன. இவை, குறிப்பிட்ட எண்ணிக்கையிலான முயற்சிகளுக்குப் பிறகு, RestartSec=-லிருந்து ஒரு குறிப்பிட்ட உச்ச வரம்பு வரை தாமதத்தை அதிகரிக்கும். Ubuntu 24.04-ல் systemd 255 இருப்பதால், இந்த வசதி உள்ளது. Debian 12-ல் systemd 252 மட்டுமே இருப்பதால், அதில் இந்த வசதி இல்லை. ஒரு dependency நீண்ட நேரம் செயலிழந்திருக்கும் சூழலில், படிப்படியாக அதிகரிக்கும் தாமதமே (growing delays) சரியான தீர்வாகும்.
"start request repeated too quickly" என்பதன் உண்மையான பொருள்
systemd தன்னிச்சையாகச் செயல்படுவதை நிறுத்திவிட்டது என்று பயனர்கள் கருதும் நிலை இது. இது ஒரு counter ஆகும். விதிமுறை இதுதான்: ஒரு unit, StartLimitIntervalSec= காலத்திற்குள் StartLimitBurst= முறைக்கு மேல் தொடங்கப்பட்டால், systemd அதை மீண்டும் தொடங்க மறுத்து, failed நிலைக்கு மாற்றும். இயல்புநிலை அமைப்புகள் 10 வினாடிகளில் 5 முறை தொடங்குவதாகும்.
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 நிலையையும் நீக்குகிறது. இதைத் தவிர வேறு எதுவும் செய்யாது, எனவே நீங்கள் அதை இயக்கும் வரை ஒரு சாதாரண systemctl start தொடர்ந்து நிராகரிக்கப்படும். கைமுறையாகத் தொடங்கும் முயற்சிகளும் இந்த வரம்பிற்குள் கணக்கிடப்படும், எனவே நீங்கள் config கோப்பைத் திருத்தும்போது சில முறை அவசரமாக systemctl restart கட்டளையை இயக்கினால், எந்தவிதமான crash-உம் இல்லாமலேயே இது தூண்டப்படலாம்.
மக்களைத் தவறாக வழிநடத்தும் பகுதி இதுதான்: start-limit-hit, service ஏன் தோல்வியடைந்தது என்பதற்கான காரணத்தைச் சொல்லாது. அது மீண்டும் மீண்டும் விரைவாகத் தோல்வியடைந்தது என்று மட்டுமே கூறுகிறது. இதற்கான உண்மையான காரணம் அதற்கு மேலே உள்ள journal வரிகளில் இருக்கும்.
இரண்டு அமைப்புகளும் [Unit] பிரிவில் இருக்க வேண்டும். பழைய systemd-ல் ஏற்றுக்கொள்ளப்பட்ட [Service] பிரிவில் இவற்றை வைக்கும் உதாரணங்களை நீங்கள் காணலாம், அங்கிருந்துதான் குழப்பம் தொடங்குகிறது. அவற்றை [Unit]-ல் எழுதுங்கள், பிறகு systemctl show மூலம் systemd எதை load செய்தது என்று கேளுங்கள், ஏனெனில் load செய்யப்பட்ட மதிப்பு மட்டுமே கணக்கில் கொள்ளப்படும்.
[Unit]
Description=My application
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=exec
ExecStart=/usr/local/bin/myapp
Restart=on-failure
RestartSec=10sஇது, unit கைவிடப்படுவதற்கு முன்பு 5 நிமிட காலத்திற்குள் ஐந்து முறை முயற்சி செய்ய அனுமதிக்கும். StartLimitIntervalSec=0 இந்த வரம்பை முழுமையாக முடக்கும், நீங்கள் எதைத் தேர்ந்தெடுக்கிறீர்கள் என்பதை அறிந்திருக்க வேண்டும்: தொடங்க முடியாத ஒரு service இனி எப்போதும் மீண்டும் மீண்டும் முயற்சிக்கும் மற்றும் ஒவ்வொரு முறையும் journal-ல் எழுதும். கணினி அளவிலான இயல்புநிலைகள் /etc/systemd/system.conf-ல் DefaultStartLimitIntervalSec= மற்றும் DefaultStartLimitBurst= என இருக்கும்.
அருகிலுள்ள ஒரு அமைப்பு எச்சரிக்கைக்குரியது. StartLimitAction=, வரம்பு எட்டப்படும்போது என்ன நடக்க வேண்டும் என்பதைத் தீர்மானிக்கிறது, இது reboot, reboot-force மற்றும் poweroff போன்ற மதிப்புகளை ஏற்கும். இயல்புநிலை none ஆகும், இது unit-ஐ தோல்வியடையச் செய்து கணினியை அப்படியே விட்டுவிடும். ஒரு remote VPS-ல், poweroff என்பது, நீங்கள் provider-ன் console-ஐத் திறக்கும் வரை கணினி அணைக்கப்பட்டே இருக்கும் என்பதைக் குறிக்கும்.
தீர்வு ஒன்று: ஒரு unit-க்கு ஒரு process
இதுவே பெரும்பாலான சிக்கல்களுக்கு தீர்வாகும். இரண்டு நிரல்கள் இயங்க வேண்டும் என்றால், இரண்டு unit-களை எழுதவும். அப்போதுதான் ஒவ்வொன்றுக்கும் தனித்தனி முதன்மை process, சரியான exit status மற்றும் அதற்கே உரிய restart policy இருக்கும். மேலும், அதிகாலை 3 மணிக்கு உங்களுக்குத் தேவைப்படும் தனித்தனி logs, தனித்தனி resource limits மற்றும் தனித்தனி restart counters ஆகியவையும் கிடைக்கும்.
Unit-களுக்கு இடையிலான தொடர்பை shell script-ல் அல்லாமல், unit file-களிலேயே குறிப்பிடவும்.
After=தொடக்கத்தை (start-up) மட்டுமே வரிசைப்படுத்தும். தோல்விகளைப் பற்றி இது எதையும் கூறாது.Requires=மற்றொரு unit-ஐ இதனுடன் சேர்த்துத் தொடங்கும்; அந்த unit வேண்டுமென்றே நிறுத்தப்பட்டால், இதையும் நிறுத்திவிடும்.BindsTo=என்பதுRequires=மற்றும் நீங்கள் கவனிக்க வேண்டிய கூடுதல் அம்சம்: ஏதேனும் ஒரு காரணத்தால் (crash உட்பட) மற்றொன்று நின்றால், இந்த unit-ம் நின்றுவிடும். இதைAfter=உடன் இணைக்கவும், இல்லையெனில் வரிசைமுறை (ordering) வரையறுக்கப்படாமல் போகும்.PartOf=நிறுத்தம் மற்றும் மறுதொடக்கத்தை (restart) கீழ்நோக்கிப் பரப்பும், இதனால்systemctl restart myapp.targetஎன்பது அதைச் சார்ந்திருக்கும் (PartOf=) அனைத்து unit-களுக்கும் சென்றடையும்.Upholds=(systemd 249 மற்றும் அதற்குப் பிந்தைய பதிப்புகள், அதாவது Ubuntu 22.04 மற்றும் அதற்குப் பிறகு) குறிப்பிட்ட unit-ஐ தொடர்ந்து இயங்க வைக்கும்: அது நின்றால், systemd அதை மீண்டும் தொடங்கும். மற்ற அனைத்தையும் போலவே இதற்கும் start rate limit பொருந்தும்.
API server இல்லாமல் இயங்கக்கூடாத ஒரு worker, மற்றும் API இயங்கும்போது அதை 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=5sஇந்த worker-க்கு [Install] பகுதி கிடையாது, இதை நீங்களாகவே enable செய்யக்கூடாது. API unit இதை Upholds= மூலம் இழுத்துக்கொள்ளும், எனவே systemctl enable --now myapp-api.service மட்டுமே நீங்கள் இயக்க வேண்டிய கட்டளை. Reload செய்து, இந்த ஜோடியை systemd எவ்வாறு கையாண்டுள்ளது என்பதைச் சரிபார்க்கவும்:
sudo systemctl daemon-reload
systemd-analyze verify /etc/systemd/system/myapp-worker.service
systemctl list-dependencies myapp-api.serviceகோப்பு சரியாக இருந்தால் systemd-analyze verify எதையும் அச்சிடாது. ஏதேனும் வெளியீடு வந்தால் அது ஒரு சிக்கல்; பெரும்பாலும் நீங்கள் எழுதிய பகுதியில் systemd அடையாளம் காணாத ஒரு key அல்லது இல்லாத ஒரு unit-ன் மீதான dependency காரணமாக இருக்கலாம்.
இரண்டாவது தீர்வு: Type=notify, PID-ஐ விட மேலாக systemd-க்குத் தெரியப்படுத்துதல்
நிரல் systemd notification protocol-ஐ ஆதரித்தால், அதைப் பயன்படுத்தவும். Type=notify மூலம், service தயாராகிவிட்டதை systemd-க்குத் தெரிவிக்கும். இது வெறும் எதிர்பார்ப்பாக இல்லாமல், முறையான வரிசைப்படுத்தலை (ordering) உறுதி செய்கிறது. மேலும், launcher-ஐக் குறிக்காமல், முக்கியமான process-ஐக் குறிக்க MAINPID=-ஐப் பயன்படுத்தலாம்.
WatchdogSec= என்பது முயற்சிக்குரிய ஒரு அம்சமாகும். இதை அமைத்தால், service குறிப்பிட்ட கால இடைவெளிக்குள் sd_notify(3) வழியாக WATCHDOG=1 செய்தியை அனுப்ப வேண்டும். செய்திகள் நின்றுவிட்டால், systemd அந்த service-ஐ SIGABRT மூலம் நிறுத்தி, failed நிலைக்கு மாற்றும். இதனால் Restart=on-failure அல்லது Restart=on-watchdog மூலம் அது மீண்டும் தொடங்கும். இயங்கிக்கொண்டிருந்தாலும் முடங்கிப்போன (stuck) ஒரு process-ஐ மீண்டும் தொடங்குவதற்கு இதுவே உள்ளமைக்கப்பட்ட ஒரே வழியாகும்; எந்த exit-status கொள்கையாலும் இதைக் கண்டறிய முடியாது.
[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/local/bin/myapp serve
WatchdogSec=30s
Restart=on-failure
RestartSec=5sWatchdog தூண்டப்பட்டால், journal-ல் myapp.service: Watchdog timeout (limit 30s)! என்ற செய்தி தோன்றி, அதன்பின் process கொல்லப்படும். மாறாக, TimeoutStartSec முடியும் வரை unit activating (start) நிலையிலேயே இருந்தால், READY=1 வந்து சேரவில்லை என்று அர்த்தம். ஒன்று, அந்த நிரல் protocol-ஐ ஆதரிக்கவில்லை, அல்லது NotifyAccess=main ஒரு child process-லிருந்து வந்த notification-ஐ நிராகரிக்கிறது. இதை journal இரண்டு PID-களுடன் பதிவு செய்யும்.
HTTP health endpoint-ஐக் கொண்டிருக்கும் ஆனால் sd_notify ஆதரவு இல்லாத மென்பொருட்களுக்கு, இரண்டு நேர்மையான வழிகள் உள்ளன: ஒன்று, endpoint-ஐச் சோதித்து systemctl restart-ஐ அழைக்கும் ஒரு சிறிய timer unit-ஐப் பயன்படுத்துவது; அல்லது container runtime-ஐக் கொண்டு சோதிப்பது. இதற்காகவே Compose healthchecks and their restart behaviour உள்ளது.
தீர்வு மூன்று: வேறு வழியில்லாதபோது, unit-க்குள் ஒரு supervisor-ஐப் பயன்படுத்துதல்
சில மென்பொருட்கள் பிரிக்க முடியாத launcher-க்கு பின்னால் பல செயல்முறைகளின் (processes) தொகுப்பாகவே வருகின்றன. அத்தகைய சூழலில், நீங்கள் unit-க்குள் ஒரு supervisor-ஐ இயக்க வேண்டும். இதன் விளைவுகளை நீங்கள் ஏற்றுக்கொண்டாக வேண்டும்: systemd அந்த supervisor-ஐக் கண்காணிக்கும், supervisor மற்ற அனைத்தையும் கண்காணிக்கும், மேலும் உங்கள் restart policy இரண்டு கோப்புகளில் அமையும்.
இதன் பொதுவான வடிவம் container runtime ஆகும். ஒரு docker compose அல்லது podman unit என்பது சரியாக இந்த அமைப்பைக் கொண்டது. இதில் container-க்கான restart policy என்பது Compose கோப்பில் குறிப்பிடப்பட்டிருக்கும், systemd unit அந்த runtime-ஐ மட்டும் இயங்க வைக்கும். உங்கள் அமைப்பு இது போன்றது என்றால், boot நேரத்தில் Compose stack-ஐ இயக்கும் unit இதற்கான சரியான முறையைக் காட்டுகிறது. இதில் ஏன் Type=oneshot உடன் RemainAfterExit=yes பயன்படுத்துவது பொதுவாகச் சரியானது என்பதும் விளக்கப்பட்டுள்ளது.
cgroup இன்னும் உங்களுக்குச் சாதகமாகவே செயல்படும். supervisor தொடங்கும் அனைத்தும் அந்த unit-ன் cgroup-க்குள்ளேயே இருக்கும். எனவே MemoryMax=, CPUQuota= மற்றும் நிறுத்தப்படும்போது செய்யப்படும் cleanup ஆகிய அனைத்தும் முழு மரத்தையும் (tree) உள்ளடக்கும். restart செய்வதற்கான முடிவு மட்டுமே மாற்றியமைக்கப்படுகிறது.
நீங்கள் எந்த supervisor-ஐத் தேர்ந்தெடுத்தாலும், வெளிப்புற unit-ல் Restart=always-ஐ அமைத்துவிட்டு, உள்ளே தீவிரமான restart policy-ஐச் சிந்திக்காமல் அமைக்க வேண்டாம். இரண்டு அடுக்குகளில் restart logic இருக்கும்போது, ஒவ்வொன்றும் அதன் சொந்த backoff-ஐக் கொண்டிருக்கும். இது சேவை பல நிமிடங்களுக்குத் தடையின்றித் துடிக்க (flapping) வழிவகுக்கும், மேலும் அதற்கான காரணத்தை journal-ல் கண்டறிவது கடினமாகிவிடும்.
ExitType=cgroup என்பது "ஏதேனும் ஒரு process நின்றால் restart செய்" என்று பொருள்படாது
ExitType= (systemd 250 மற்றும் அதற்குப் பிந்தைய பதிப்புகள், எனவே Ubuntu 24.04 மற்றும் Debian 12 இரண்டிலும் இது உள்ளது) என்பது இந்தச் சிக்கலைத் தேடும்போது பயனர்கள் கண்டறியும் அமைப்பாகும், ஆனால் இது பெயருக்கு மாறான செயல்பாட்டையே செய்கிறது. இயல்புநிலை அமைப்பான ExitType=main, முதன்மை process வெளியேறும்போது service நிறுத்தப்பட்டதாகக் கருதப்படும் என்பதைக் குறிக்கிறது. ExitType=cgroup என்பது cgroup-ல் உள்ள கடைசி process வெளியேறும் வரை service இயங்கிக்கொண்டிருப்பதாகக் கருதப்படும் என்பதைக் குறிக்கிறது.
எனவே, ExitType=cgroup என்பது ஒரு process நின்றால் service-ஐ பாதிக்காதவாறே செயல்படுகிறது, மாறாக அதிக உணர்திறன் கொண்டதாக மாற்றாது. PID file-ஐ உருவாக்காமல் தனது உண்மையான worker process-ஐ fork செய்துவிட்டு, parent process-ஐ முடித்துக்கொள்ளும் நிரல்களுக்கு இதுவே சரியான அமைப்பாகும்; ஏனெனில் அத்தகைய சூழலில் Type=forking-ஆல் daemon-ஐக் கண்டறிய முடியாது. இங்கே விவரிக்கப்பட்டுள்ள தோல்விக்கு இது தவறான அமைப்பாகும்.
"cgroup-ல் உள்ள ஏதேனும் ஒரு process நின்றால் unit-ஐ restart செய்" என்று பொருள்படும் Restart= மதிப்பு எதுவும் இல்லை. உங்களுக்கு அத்தகைய செயல்பாடு தேவைப்பட்டால், ஒரு unit-க்கு ஒரு process என்ற அடிப்படையில் அமைக்க வேண்டும். நிரலைப் பிரிக்க முடியாமல், wrapper script-ஐ நீங்கள் கட்டுப்படுத்துகிறீர்கள் என்றால், அதற்கு நெருக்கமான வழி wait -n ஆகும், இது முதல் child process வெளியேறியவுடன் திரும்பும்:
#!/bin/bash
/usr/local/bin/myapp-web &
/usr/local/bin/myapp-worker &
wait -n
exit 1இப்போது ஏதேனும் ஒரு child process நின்றாலும், அது wrapper-ஐ non-zero status-உடன் கீழே கொண்டு வரும், அதனால் Restart=on-failure செயல்படும். இது ஒரு தற்காலிகத் தீர்வே தவிர, முழுமையான சரிசெய்தல் அல்ல. இதில் இரண்டு நிரல்களுக்கும் ஒரே restart counter மற்றும் ஒரே log stream மட்டுமே இருக்கும், மேலும் தோல்வியடையும் பாதியை மட்டும் தனியாக restart செய்ய முடியாது.
உண்மையில் என்ன நடந்தது என்பதை ஆய்வு செய்வது எப்படி
இந்த வரிசையில் நான்கு கட்டளைகள் உள்ளன.
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 ஒரு திரையில் service-ன் நிலை, முதன்மை PID மற்றும் cgroup படிநிலையைக் காட்டும். சரியாக இயங்கும் ஒரு unit, Active: active (running) என்ற நிலையையும், நீங்கள் எதிர்பார்க்கும் process-ஐக் குறிப்பிடும் Main PID: வரியையும் கொண்டிருக்கும். கீழே உள்ள படிநிலையில் உங்களுக்குத் தெரியாத process-கள் இருந்தாலோ அல்லது நீங்கள் எதிர்பார்க்கும் process விடுபட்டிருந்தாலோ, அதற்கான விடை உங்களுக்குக் கிடைத்துவிடும்.
systemd-cgls --unit அதே படிநிலையைச் சுருக்காமல் முழுமையாக அச்சிடும். ஒரு unit-ல் பல process-கள் இயங்கும்போது இது முக்கியமானது.
systemctl show கணினியால் வாசிக்கக்கூடிய தகவல்களை வழங்கும். NRestarts= என்பது restart எண்ணிக்கையைக் குறிக்கும். ஒரு service 40 முறை restart ஆகியுள்ளதா அல்லது boot செய்ததிலிருந்து இயங்குகிறதா என்பதை அறிய இதுவே அதிவேகமான வழி. Result= கடைசி தோல்விக்கான காரணத்தைக் கொண்டிருக்கும்: exit-code, signal, timeout, oom-kill, watchdog அல்லது start-limit-hit. ExecMainStatus= என்பது கடைசியாக இயங்கிய முதன்மை process-ன் raw exit status ஆகும்.
Journal-ல் வரிசைமுறை பதிவுகள் இருக்கும். தேட வேண்டிய மூன்று வரிகள் இவை:
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 என்றால், நிரல் N என்ற குறியீட்டைத் திரும்ப அனுப்பியுள்ளது என்று பொருள்; எனவே பிழை நிரலிலோ அல்லது அதன் configuration-லோ உள்ளது. code=killed, signal=SEGV என்றால் அது crash ஆகியுள்ளது என்று பொருள். code=killed, signal=TERM என்பது பொதுவாக வேறொரு காரணி அதை நிறுத்தச் சொன்னதைக் குறிக்கும்; இது தோல்வி அல்ல, எனவே இது Restart=on-failure-ஐத் தூண்டாது. code=dumped என்றால் அது core file-ஐ விட்டுச் சென்றுள்ளது என்று பொருள்; systemd-coredump நிறுவப்பட்டிருந்தால், coredumpctl list மூலம் அதை நீங்கள் பார்க்கலாம்.
ஒன்றுக்கும் மேற்பட்ட server-களில், NRestarts என்பது குறிப்பிட்ட கால இடைவெளியில் சேகரிக்க வேண்டிய முக்கியமான எண். ஒரு unit-ன் counter தினமும் அதிகரித்தால், அது தினமும் தோல்வியடைகிறது என்று பொருள்; யாராவது கவனித்தார்களோ இல்லையோ, அது தோல்வியடைகிறது. இரண்டு அல்லது மூன்று server-களுக்கு மேல் செல்லும்போது, ஒவ்வொரு server-லும் ஒரே கட்டளையை இயக்கும் சீரான வழி இதைக் வெறும் ஊகமாக இல்லாமல் ஒரு அறிக்கையாக மாற்றும்.
FAQ
service-ன் process செயலிழந்த பிறகும், systemctl ஏன் அது active நிலையில் இருப்பதாகக் காட்டுகிறது?
systemd ஒவ்வொரு service unit-க்கும் ஒரு முதன்மை process-ஐ மட்டுமே கண்காணிக்கும். Restart= அந்த process-ன் exit status-ஐ மட்டுமே வாசிக்கும். அந்த unit தொடங்கும் மற்ற அனைத்து process-களும் ஒரே cgroup-ல் இருக்கும். unit நிறுத்தப்படும்போது systemd அவற்றை அழித்துவிடும், ஆனால் அவை வெளியேறுவதை அது கண்காணிப்பதில்லை. systemctl show -p MainPID myapp.service கட்டளையை இயக்கி, அதன் எண்ணிக்கையை systemd-cgls --unit myapp.service உடன் ஒப்பிடவும். செயலிழந்த process அந்த tree-ல் இருந்து, அது MainPID நிலையில் இல்லை என்றால், systemd தனது வடிவமைப்பின்படியே செயல்படுகிறது என்று அர்த்தம். இதற்குத் தீர்வாக, ஒரு unit-க்கு ஒரு process மட்டுமே இருக்க வேண்டும். unit-களுக்கு இடையிலான தொடர்பை BindsTo= மற்றும் Upholds= மூலம் வரையறுக்க வேண்டும்.
"start request repeated too quickly" என்பதன் பொருள் என்ன?
ஒரு unit, StartLimitIntervalSec= காலத்திற்குள் StartLimitBurst= முறைக்கு மேல் தொடங்க முயற்சித்துள்ளது என்று பொருள். இயல்பாக இது 10 வினாடிகளில் 5 முறை தொடங்குவதைக் குறிக்கும்; எனவே systemd முயற்சியைக் கைவிட்டுவிடும். இது ஒரு rate limit மட்டுமே; service ஏன் தோல்வியடைகிறது என்பதற்கான காரணத்தை இது கூறாது. எனவே, அதற்கு முந்தைய journal வரிகளைப் படிக்கவும். systemctl reset-failed myapp.service மூலம் நிலையை (state) நீக்கிவிட்டு, அடிப்படைத் தோல்வியைச் சரிசெய்யவும். ஒரு service தொடங்குவதற்கு அதிக நேரம் எடுக்கும் என்றால், RestartSec= மதிப்பை அதிகரிக்கவும். ஏனெனில், இயல்பான 100 milliseconds இடைவெளி, ஐந்து முயற்சிகளையும் ஒரு வினாடிக்குள் முடித்துவிடும்.
நான் Restart=always அல்லது Restart=on-failure எதைப் பயன்படுத்த வேண்டும்?
பெரும்பாலானவற்றிற்கு on-failure பயன்படுத்தவும். இது crash, non-zero exit, timeout மற்றும் watchdog trip ஆகியவற்றைச் சரிசெய்து மீண்டும் தொடங்கும்; அதேசமயம் திட்டமிட்டு செய்யப்படும் exit 0-ஐ இது பாதிக்காது. ஒரு நிரல் தனது கட்டுப்பாட்டிற்கு அப்பாற்பட்ட காரணங்களால் (உதாரணமாக, peer disconnect ஆகும்போது 0 எனத் திரும்பும் client) சரியாக வெளியேறினால் மட்டுமே always பயன்படுத்தவும். always-ன் குறைபாடு என்னவென்றால், தவறான configuration-ஐ வாசித்து, ஒரு error-ஐப் பதிவு செய்துவிட்டு 0 என வெளியேறும் service, முடிவில்லாமல் சுழன்று கொண்டே இருக்கும். இதன் அறிகுறி systemctl show-ல் NRestarts அதிகரித்துக்கொண்டே இருப்பது மட்டுமே.
எனது process-ஐ நான் கைமுறையாகக் கொல்லும்போது (kill) ஏன் restart தூண்டப்படுவதில்லை?
ஏனெனில் systemd, SIGHUP, SIGINT, SIGTERM மற்றும் SIGPIPE ஆகியவற்றைச் சரியான வெளியேற்றமாக (clean exit) கருதுகிறது. சாதாரண kill <pid> கட்டளை SIGTERM-ஐ அனுப்பும். Restart=on-failure விதியின்படி, சரியான வெளியேற்றம் தோல்வியாகக் கருதப்படாது. எனவே, restart நடக்காது; configuration சரியாக இருந்தாலும் அது பழுதடைந்தது போலத் தோன்றும். kill -9 <pid> அல்லது systemctl kill -s SIGKILL myapp.service மூலம் சோதிக்கவும்; இது முறையற்ற வெளியேற்றத்தைத் தூண்டி, restart கொள்கையைச் செயல்படுத்தும். இதே விதிதான் systemctl stop ஏன் உங்கள் restart கொள்கையைத் தடுப்பதில்லை என்பதையும் விளக்குகிறது.
StartLimitIntervalSec மற்றும் StartLimitBurst ஆகியவற்றை எங்கே சேர்க்க வேண்டும்?
இவற்றை [Unit] பகுதியில் சேர்க்க வேண்டும். பழைய ஆவணங்கள் மற்றும் பழைய systemd பதிப்புகளில் இவை [Service] பகுதியில் இருந்தன, அதனால் நகலெடுக்கப்பட்ட உதாரணங்களில் முரண்பாடுகள் இருக்கலாம். உங்கள் பதிப்பு எதை ஆதரிக்கிறது என்று யூகிக்க வேண்டாம். systemctl daemon-reload செய்த பிறகு, systemctl show -p StartLimitBurst -p StartLimitIntervalUSec myapp.service மூலம் systemd எதை ஏற்றுக்கொண்டது என்று சரிபார்க்கவும்; அந்த எண்களையே உண்மையாகக் கொள்ளவும். systemd-analyze verify /etc/systemd/system/myapp.service கட்டளை systemd-க்குத் தெரியாத keys-ஐக் கண்டறியும்; கோப்பு சரியாக இருந்தால் அது எதையும் காட்டாது.