تفاوت Type در systemd: simple، forking و notify
اگر سرویس شما در وضعیت active است اما پردازش اصلی متوقف شده، باید Type را اصلاح کنید. تفاوت دقیق simple، forking و notify را برای مدیریت درست PIDها بیاموزید.
Why does systemd report a unit as active when the process died
A systemd service unit stays active while the one process systemd calls the main process is alive, and Type= in the [Service] section decides which process that is. Pick the wrong value and systemd ends up watching a shell wrapper or a short lived parent while the daemon you care about dies inside the same unit. The unit is telling you the truth about the process it was told to watch.
Changing the restart policy will not help here. Restart= acts when the main process exits, so Restart=always never fires while the main PID (process identifier) belongs to something that is still running. Fix Type= first. What systemd does after the main process really exits is a separate decision, covered in the guide to Restart= and RestartSec=.
پارامتر Type= دقیقاً چه چیزی را تعیین میکند
هر مقدار Type= همزمان به دو پرسش پاسخ میدهد. چه زمانی systemd باید این واحد را «شروعشده» در نظر بگیرد، و کدام پردازش، پردازش اصلی است.
پاسخ نخست، ترتیب اجرا (ordering) را کنترل میکند. واحدی که نام واحد شما را در After= ذکر کرده است، منتظر میماند تا systemd واحد شما را «شروعشده» اعلام کند. یک Type= که وضعیت "started" را خیلی زود گزارش دهد، باعث میشود واحدهای وابسته پیش از آنکه سرویس شما آمادهٔ پاسخگویی باشد، اجرا شوند.
پاسخ دوم، نظارت (supervision) را کنترل میکند. systemd تمام پردازشهایی را که یک واحد ایجاد میکند، در یک cgroup (گروه کنترل) قرار میدهد؛ قابلیتی در هسته که پردازشها را دستهبندی میکند تا بتوان آنها را محدود کرد یا با هم خاتمه داد. cgroup همان روشی است که systemctl stop برای پاکسازی استفاده میکند: KillMode= بهصورت پیشفرض روی control-group تنظیم شده است، بنابراین متوقف کردن یک واحد، به تمام پردازشهای درون آن سیگنال ارسال میکند. PID اصلی محدودتر است. این همان پردازش واحدی است که خروجش به معنای پایان واحد است و وضعیت خروج آن، نتیجهٔ نهایی واحد را تعیین میکند. خواندن cgroup به شکلی که گویی همان PID اصلی است، منشأ اصلی سردرگمیهاست.
نوع simple پیش از اجرای فایل باینری آغاز میشود
Type=simple مقدار پیشفرض است زمانی که ExecStart= تنظیم شده باشد و هیچکدام از Type= یا BusName= موجود نباشند. systemd پردازش را ایجاد میکند، واحد (unit) را بلافاصله شروعشده در نظر میگیرد و آن پردازش را به عنوان PID اصلی تلقی میکند. واحدهای بعدی بلافاصله شروع میشوند، حتی پیش از آنکه فایل باینری سرویس اجرا شده باشد.
این جزئیات آخر، یک غافلگیری رایج را توضیح میدهد. یک غلط تایپی در مسیر ExecStart= همچنان منجر به ایجاد یک job شروع میشود که موفقیتآمیز است، و خطا لحظاتی بعد هنگام اجرای برنامه رخ میدهد. systemd این مورد را با کد خروج 203 ثبت میکند که در جدول خودش با نام EXEC شناخته شده و به عنوان عدم موفقیت در اجرای فایل باینری سرویس تعریف میشود. بنابراین، بازگشت موفقیتآمیز systemctl start ثابت نمیکند که فایل باینری شما وجود دارد.
برای برنامهای که در پیشزمینه (foreground) باقی میماند و هرگز خود را به پسزمینه منتقل نمیکند، از simple استفاده کنید. این مورد اکثر دیمونهای مدرن و تقریباً هر چیزی که خودتان مینویسید را پوشش میدهد.
نوع Type=exec منتظر میماند تا برنامه واقعاً اجرا شود
Type=exec همان simple است با یک گام اضافه. systemd تنها زمانی واحد (unit) را شروعشده تلقی میکند که هم fork و هم اجرای فایل باینری با موفقیت انجام شده باشند. نبود فایل باینری یا یک User= که قابل حل نباشد، اکنون باعث شکست خودِ job شروع میشود؛ بهجای اینکه وضعیت موفقیت گزارش شود و لحظاتی بعد سرویس بیسروصدا از کار بیفتد.
Type=exec در systemd 240 معرفی شد، بنابراین تمام توزیعهای سروری فعلی آن را دارند. تا اوت 2026، Ubuntu 24.04 با systemd 255 و Debian 13 با systemd 257 عرضه میشوند. نسخه خود را با systemctl --version بررسی کنید.
هزینه این کار، یک گام همگامسازی اضافه در هنگام شروع است. دستاورد آن، دریافت یک وضعیت خروج (exit status) دقیق از systemctl start است. برای برنامههای foreground، استفاده از exec را به simple ترجیح دهید.
نوع Type=forking و نحوه گم شدن PID اصلی
Type=forking به systemd میگوید که پردازشی که در ExecStart= تعریف شده، یک پردازش فرزند ایجاد میکند و سپس عمداً خاتمه مییابد. systemd منتظر میماند تا آن پردازش اولیه خارج شود و تنها پس از آن، واحد (unit) را در وضعیت started قرار میدهد. پردازش فرزندی که باقی میماند، همان daemon است. این عادت از دوران SysV باقی مانده است؛ زمانی که پس از بازگشت اسکریپت init، هیچ نظارتی بر daemon وجود نداشت و فایل PID تنها سابقه موجود از پردازش در حال اجرا بود. این محدودیت، یکی از دلایل اصلی جایگزینی اسکریپتهای init توسط systemd است.
مشکل اصلی، شناسایی هویت است. پردازشی که systemd اجرا کرده بود از بین رفته است، بنابراین systemd باید تشخیص دهد کدامیک از پردازشهای باقیمانده، پردازش اصلی است. مقدار PIDFile= را روی فایلی تنظیم کنید که daemon در آن مینویسد (معمولاً مسیری در /run) تا systemd بتواند PID را از آن بخواند. همچنین systemd بررسی میکند که آیا PID موجود در آن فایل به پردازشی تعلق دارد که قبلاً بخشی از این سرویس بوده است یا خیر؛ بنابراین، فایلهای قدیمی که به پردازشهای نامرتبط اشاره میکنند، رد میشوند و به آنها اعتماد نمیشود.
بدون PIDFile=، گزینه GuessMainPID= اعمال میشود که مقدار پیشفرض آن yes است. این حدس زدن تنها زمانی قابلاطمینان است که سرویس به یک پردازش واحد محدود شود. مستندات بهصراحت این محدودیت را بیان میکنند: اگر daemon شامل بیش از یک پردازش باشد، ممکن است حدس systemd اشتباه باشد و تشخیص خرابی (failure detection) از کار بیفتد. همچنین ممکن است یک واحد با PID اصلی 0 باقی بماند، که به این معنی است که systemd هیچ پردازشی برای نظارت ندارد.
بیشتر daemonهایی که از قابلیت fork استفاده میکنند، سوئیچی دارند که آنها را در foreground نگه میدارد. از آن سوئیچ در Type=exec استفاده کنید و خط PIDFile= را حذف کنید. کاهش قطعات متحرک به معنای کاهش احتمال گم شدن PID است.
نوع Type=oneshot برای کارهایی که به پایان میرسند
Type=oneshot انتظار دارد که پردازش اجرا شود و سپس خاتمه یابد. systemd تنها پس از خروج پردازش، واحد را «شروعشده» تلقی میکند؛ این ویژگی باعث میشود oneshot ساختار مناسبی برای هر کاری باشد که واحد دیگری باید منتظر اتمام آن بماند. همچنین، زمانی که واحد هیچکدام از مقادیر Type= یا ExecStart= را مشخص نکند، این حالت بهصورت پیشفرض در نظر گرفته میشود.
دو رفتار خاص برای oneshot وجود دارد. این تنها نوعی است که بیش از یک خط ExecStart= را میپذیرد و آن خطوط به ترتیب اجرا میشوند. همچنین، مهلت زمانی شروع (start timeout) در این حالت بهصورت پیشفرض غیرفعال است، بنابراین اگر یک oneshot متوقف شود (hang)، تا ابد منتظر میماند مگر اینکه خودتان مقدار TimeoutStartSec= را تنظیم کنید.
پس از خروج پردازش، واحد به وضعیت غیرفعال (inactive) بازمیگردد. RemainAfterExit=yes آن را در وضعیت active نگه میدارد، بدون اینکه پردازشی در حال اجرا باشد. این نسخهٔ عمدی از علائمی است که در ابتدای این صفحه ذکر شد و زمانی صحیح است که وظیفهٔ واحد، باقی گذاشتن یک وضعیت (state) باشد نه اجرای مداوم یک سرویس؛ مانند بارگذاری مجموعهای از قوانین فایروال یا بالا آوردن یک stack از کانتینرها. این همان الگویی است که در یک Docker Compose stack که پس از reboot دوباره بالا میآید استفاده میشود؛ جایی که واحد دستور compose را اجرا میکند، خارج میشود و فعال باقی میماند زیرا کانتینرهایی که شروع کرده است، پس از پایان کار واحد همچنان به حیات خود ادامه میدهند. یک واحد oneshot همچنین همان چیزی است که توسط زمانبند (schedule) فراخوانی میشود؛ که بخش دیگر اجرای یک job روی systemd timer بهجای cron است.
استفاده از Type=notify به سرویس اجازه میدهد زمان آمادهبهکار بودن خود را اعلام کند
Type=notify تصمیمگیری را به خود سرویس واگذار میکند. systemd عملیات شروع (start job) را باز نگه میدارد تا زمانی که پردازش، پیام READY=1 را از طریق یک Unix socket ارسال کند؛ مسیری که سرویس از طریق متغیر محیطی NOTIFY_SOCKET دریافت میکند. رابط C برای این کار sd_notify(3) است و بسیاری از سرورها از قبل از آن پشتیبانی میکنند.
این دقیقترین پاسخ به پرسش «آیا سرویس شروع شده است؟» محسوب میشود. simple و exec وضعیت شروع را پیش از آنکه سرویس فایل پیکربندی خود را خوانده یا socket شنود (listening socket) را باز کرده باشد گزارش میدهند؛ در نتیجه، یک واحد وابسته ممکن است خیلی زود شروع به کار کرده و در اولین اتصال خود با شکست مواجه شود. notify وضعیت شروع را دقیقاً در لحظهای گزارش میدهد که خودِ سرویس اعلام آمادگی میکند.
systemd این پیام را تنها از پردازش اصلی (main process) میپذیرد که معنای NotifyAccess=main است و Type=notify نیز همین موضوع را القا میکند. اگر پیام از یک پردازش فرزند یا کمکی ارسال میشود، باید NotifyAccess=all را تنظیم کنید. یک اسکریپت shell میتواند systemd-notify --ready را فراخوانی کند، اما چون این کار به عنوان یک پردازش مجزا و کوتاهمدت اجرا میشود، به NotifyAccess=all نیاز دارد و ممکن است systemd نتواند پیامی را که فرستندهاش قبلاً خاتمه یافته است، به سرویس اصلی نسبت دهد. سرویسی که خود مستقیماً با این پروتکل صحبت میکند، قابلاطمینانتر است.
دو تنظیم مرتبط دیگر نیز ارزش دانستن دارند. Type=notify-reload که از نسخه systemd 253 در دسترس است، همین دستدادن (handshake) را به عملیات reload نیز تعمیم میدهد؛ بنابراین systemctl reload زمانی بازمیگردد که سرویس گزارش دهد عملیات reload به پایان رسیده است، نه زمانی که سیگنال ارسال شده است. WatchdogSec= از یک سرویسِ اطلاعرسان (notifying service) میخواهد که در فواصل زمانی مشخص، یک پیام keep-alive ارسال کند و systemd در صورت از دست رفتن مهلت زمانی، آن را به عنوان یک شکست در نظر میگیرد.
Type=dbus و Type=idle
Type=dbus تا زمانی که سرویس نامی را روی D-Bus ثبت نکند منتظر میماند؛ D-Bus همان message bus است که سرویسهای سیستم و دسکتاپ برای ارتباط با یکدیگر از آن استفاده میکنند. این گزینه به BusName= نیاز دارد و به محض تنظیم BusName=، به حالت پیشفرض تبدیل میشود. از این گزینه فقط برای سرویسی استفاده کنید که واقعاً یک نام روی bus ثبت میکند.
Type=idle مشابه simple عمل میکند، اما اجرای برنامه را تا زمانی که jobهای در صف پردازش شوند به تأخیر میاندازد (با محدودیت زمانی پنج ثانیه). این گزینه برای این وجود دارد که خروجی کنسول در هنگام boot با پیامهای وضعیت تداخل پیدا نکند. این یک ابزار برای تعیین ترتیب (ordering) نیست و نباید در سرویسهای معمولی استفاده شود.
چرا اسکریپت wrapper باعث میشود 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 در پیشزمینه اجرا میشود، زنده میماند. اگر server از کار بیفتد، پوسته متوجه نمیشود؛ بنابراین PID اصلی همچنان زنده است، وضعیت unit همچنان active باقی میماند و Restart= چیزی برای اقدام کردن ندارد. هر دو پردازش در تمام مدت در cgroup مربوط به unit باقی میمانند، بنابراین systemctl stop همچنان پاکسازی را به درستی انجام میدهد. آنچه دچار اختلال شده، نظارت (supervision) است، نه پاکسازی.
راه حل به تعداد پردازشهای طولانیمدت (long-running) موجود در unit بستگی دارد.
اگر تنها یک پردازش وجود دارد، پوسته را با آن جایگزین کنید.
#!/bin/bash
export APP_ENV=production
exec /opt/app/bin/server --config /etc/app.yamlexec پوسته را با برنامه نامبرده جایگزین میکند و همان PID را حفظ میکند، بنابراین PID که systemd ثبت کرده است اکنون متعلق به daemon است. بهتر از آن، wrapper را حذف کنید. Environment= و EnvironmentFile= متغیرها را منتقل میکنند و ExecStartPre= مرحله راهاندازی را انجام میدهد، بنابراین systemd میتواند daemon را مستقیماً اجرا کند و PID آن را از طریق ساختار فراخوانی بشناسد.
اگر دو پردازش وجود دارد، هیچ PID واحدی نماینده unit نیست. آنها را به دو unit مجزا تقسیم کنید و با استفاده از After= و Wants= ترتیب اجرای آنها را مشخص کنید. یک unit برای هر پردازش، آرایشی است که systemd به خوبی بر آن نظارت میکند و این تنها راهی است که هر پردازش رفتار راهاندازی مجدد (restart) خاص خود را داشته باشد.
تغییرات ExitType=cgroup
ExitType= در نسخه 250 از systemd اضافه شد. مقدار پیشفرض main است: واحد (unit) زمانی متوقف تلقی میشود که پردازش اصلی (main process) خاتمه یابد. با استفاده از ExitType=cgroup، واحد تا زمانی که هر پردازشی در cgroup آن زنده باشد، در حال اجرا در نظر گرفته میشود.
[Service]
Type=simple
ExitType=cgroup
ExecStart=/opt/app/launcherاین تنظیم یک مشکل خاص را حل میکند. تحت ExitType=main، اگر یک راهانداز (launcher) کار اصلی را شروع کرده و سپس خارج شود، systemd واحد را متوقفشده تلقی کرده و پردازشهای باقیمانده را میکشد. با ExitType=cgroup، واحد کل گروه را دنبال میکند.
دقت کنید که این تنظیم چه چیزی را حل نمیکند. ExitType=cgroup واحد را تا زمانی که حداقل یک پردازش زنده باشد فعال نگه میدارد، بنابراین واحدی که دو daemon را مدیریت میکند، پس از مرگ یکی از آنها همچنان فعال میماند. این تنظیم مشکل راهانداز را حل میکند، اما یک واحد را به ناظر چندین پردازش مستقل تبدیل نمیکند. همچنین ExitType= با Type=oneshot قابل ترکیب نیست.
cgroup جایی است که حسابرسی منابع نیز در آن انجام میشود، بنابراین محدودیتهایی مانند MemoryMax= و CPUQuota= بر تمام پردازشهایی که واحد ایجاد کرده اعمال میشود، فارغ از اینکه Type= درباره PID اصلی چه میگوید. آن بخش از موضوع در محدود کردن حافظه و CPU سرویس با systemd آمده است.
نحوه یافتن فرآیندی که systemd واقعاً در حال نظارت بر آن است
این مراحل را به ترتیب روی واحدی که در حال عیبیابی آن هستید، انجام دهید. ابتدا آنچه را که systemd بارگذاری کرده بخوانید، سپس آنچه را که ردیابی میکند بررسی کنید و در نهایت آن را با جدول فرآیندها مقایسه نمایید.
systemctl cat app.service
systemctl show -p Type,ExitType,GuessMainPID,PIDFile,MainPID,RemainAfterExit app.serviceدستور systemctl cat فایل واحد را به همراه تمام drop-inهایی که روی آن اعمال میشوند چاپ میکند؛ بنابراین شما آنچه را که systemd واقعاً بارگذاری کرده میخوانید، نه فایلی که در ذهن دارید ویرایش کردهاید. دستور systemctl show مقادیر مؤثر، شامل پیشفرضهایی که هرگز یادداشت نکردهاید را چاپ میکند. پیش از ادامه، مقدار MainPID را یادداشت کنید.
systemd-cgls --unit=app.service
ps -o pid,ppid,stat,etime,args -p "$(systemctl show -p MainPID --value app.service)"دستور systemd-cgls تمام فرآیندهای موجود در cgroup واحد را فهرست میکند. خط ps تکفرآیندی را که systemd بر آن نظارت دارد توصیف میکند. این دو را با هم بخوانید. مقدار MainPID برابر با 0 به این معنی است که systemd هیچ فرآیندی برای نظارت ندارد. اگر MainPID به یک shell اشاره کند در حالی که cgroup شامل daemon شما نیز هست، با مورد wrapper که در بالا ذکر شد مواجه هستید. وجود فرآیندهای بیشتر از حد انتظار در یک cgroup به این معنی است که یک launcher یا یک daemon از نوع forking درگیر است.
systemctl status app.service
journalctl -u app.service -bدستور systemctl status خط وضعیت و درخت cgroup را با هم چاپ میکند، بنابراین اغلب پاسخ هر دو پرسش را یکجا میدهد. دستور journalctl -u که با -b به همین boot محدود شده است، رویدادهای شروع و توقفی را که systemd برای آن واحد ثبت کرده، به همراه کدهای خروجی مشاهدهشده نشان میدهد. اگر daemon به جای journal در فایل لاگ اختصاصی خود مینویسد، آن فایل را نیز بخوانید، زیرا systemd فقط میتواند آنچه را که به دستش رسیده ثبت کند.
هنگامی که Type= را تغییر میدهید، reload و restart کنید.
systemd-analyze verify /etc/systemd/system/app.service
sudo systemctl daemon-reload
sudo systemctl restart app.serviceدستور systemd-analyze verify فایل را تجزیه کرده و تنظیماتی را که نمیتواند بپذیرد گزارش میدهد. دستور daemon-reload باعث میشود systemd فایلهای واحد را دوباره از دیسک بخواند. تغییر در Type= روی واحدی که از قبل در حال اجراست اعمال نمیشود، بنابراین restart الزامی است و اختیاری نیست.
سپس تغییر را تست کنید. PID فرآیندی که واقعاً مد نظر شماست را از systemd-cgls بردارید و آن را kill کنید. بلافاصله پس از آن systemctl is-active app.service را اجرا کنید. اگر Type= درست باشد، واحد از وضعیت active خارج میشود. اگر همچنان active باقی بماند، یعنی systemd هنوز در حال نظارت بر چیز دیگری است.
از کدام Type= در سرویس systemd استفاده کنید
- برنامهای که در پیشزمینه (foreground) باقی میماند:
Type=exec. - برنامهای که از اعلان آمادگی (readiness notification) پشتیبانی میکند:
Type=notify، و اگر بازخوانی (reload) را نیز تأیید میکند:notify-reload. - دیمونی (daemon) که اصرار دارد به پسزمینه (background) برود:
Type=forkingبه همراهPIDFile=، یا استفاده از سوییچ پیشزمینه آن باType=exec. - اسکریپتی که کاری را انجام داده و خارج میشود:
Type=oneshot، به علاوهRemainAfterExit=yesزمانی که هدف، باقی ماندن وضعیت (state) باشد. - راهاندازی (launcher) که خارج میشود در حالی که فرزندانش به اجرا ادامه میدهند:
Type=simpleبه همراهExitType=cgroup.
اگر مطمئن نیستید که یک دیمون شخص ثالث به کدام نوع نیاز دارد، ابتدا فایل unit بستهبندیشده آن را بخوانید. اجرای systemctl cat روی یک unit که توسط توزیع ارائه شده است، Type= انتخابشده توسط توسعهدهنده اصلی را نشان میدهد؛ این انتخاب توسط افراد بیشتری نسبت به شما تست شده است.
FAQ
چرا unit سیستمدی (systemd) با وجود مرگ پردازش، همچنان active باقی میماند؟
زیرا پردازشی که سیستمدی آن را به عنوان پردازش اصلی (main) در نظر میگیرد، همچنان زنده است. سیستمدی به جای نظارت بر تمام پردازشهای موجود در cgroup مربوط به unit، تنها یک PID را بر اساس Type= زیر نظر میگیرد. علت معمول این اتفاق، استفاده از یک اسکریپت wrapper است که با Type=simple اجرا شده: در این حالت، shell همان PID اصلی است و بنابراین وقتی daemonای که توسط shell در پسزمینه اجرا شده متوقف میشود، unit همچنان active باقی میماند. دستور systemctl show -p MainPID app.service را اجرا کنید، سپس cgroup مربوط به unit را با systemd-cgls --unit=app.service لیست کرده و این دو را با هم مقایسه کنید.
تفاوت بین Type=simple و Type=exec چیست؟
در Type=simple، به محض اینکه سیستمدی پردازش را ایجاد کند، unit به عنوان شروعشده در نظر گرفته میشود؛ این اتفاق پیش از اجرای فایل باینری رخ میدهد، بنابراین اگر مسیر در ExecStart= اشتباه باشد، همچنان یک start job موفق گزارش میشود و پس از آن شکست رخ میدهد. در Type=exec، سیستمدی منتظر میماند تا اجرا با موفقیت انجام شود، بنابراین شکست مستقیماً توسط همان start job گزارش خواهد شد. هر دو گزینه، یک پردازش واحد را به عنوان PID اصلی در نظر میگیرند. Type=exec به سیستمدی نسخه 240 یا جدیدتر نیاز دارد.
آیا در Type=forking همچنان به PIDFile= نیاز دارم؟
بله، هر زمان که daemon فایلی برای PID مینویسد، به آن نیاز دارید. بدون آن، سیستمدی به GuessMainPID= متوسل میشود که یک حدس است و تنها برای سرویسهایی که به یک پردازش واحد محدود میشوند، قابلاطمینان است. وقتی این حدس اشتباه باشد یا غیرممکن باشد، تشخیص شکست و راهاندازی مجدد خودکار برای آن unit از کار میافتد. مقدار PIDFile= را دقیقاً روی مسیری تنظیم کنید که daemon در آن مینویسد؛ این مسیر معمولاً زیرشاخه /run است.
چه زمانی باید از RemainAfterExit=yes استفاده کنم؟
زمانی که هدف unit تغییر وضعیت سیستم باشد، نه حفظ یک پردازش در حال اجرا. یک unit از نوع Type=oneshot که قوانین فایروال را بارگذاری میکند یا یک stack از کانتینرها را بالا میآورد، به محض اتمام کارش خارج میشود. بدون RemainAfterExit=yes، وضعیت unit به inactive تغییر میکند که باعث میشود systemctl stop چیزی برای متوقف کردن نداشته باشد و راهی برای اجرای عملیات پاکسازی ExecStop= باقی نماند. با فعال کردن این گزینه، unit بدون داشتن هیچ پردازشی در وضعیت active باقی میماند که در این سناریو، رفتار مورد انتظار است.
آیا تغییر Type= نیاز به daemon-reload دارد؟
بله، و علاوه بر آن نیاز به restart کردن خودِ unit نیز هست. systemctl daemon-reload باعث میشود سیستمدی فایلهای unit موجود روی دیسک را دوباره بخواند، اما نمونهای که در حال اجراست همچنان از Type=ای که با آن شروع شده استفاده میکند. پیش از تست کردن، دستور sudo systemctl daemon-reload و سپس sudo systemctl restart app.service را اجرا کنید؛ در غیر این صورت، همچنان رفتار نظارتی قدیمی را مشاهده خواهید کرد.