[Linux] Systemctl stop 時,被 service 叫起來的 process 都不見了?
今天遇到一個 systemd 的問題~
我們的程式是跑在另一個專案的機器上面,它們的一個 systemd 的 main service 會呼叫我們的 CLI,
而我們的 CLI 會把一些 daemon 叫起來,接著 CLI 就結束,留 daemon 在背景執行~
平常在 terminal 裡面單獨執行 CLI 時,這些 daemon 並不會因為 CLI 結束而結束,
但是用那個 main service 來呼叫 CLI 的話,執行 systemctl stop main 就會把我們的 daemon 都砍掉…
找了一下,有人跟我遇到同樣的問題,原來是 systemd 設定上的問題~
預設狀況下,systemctl stop 時會對同一個 control group (cgroup) 的所有 process,
都送出一個 SIGTERM,所以本例中我們的 daemon 就會都跟著下去了…
舉個例子來看,先用 systemctl status main 看看 main service 的狀態,
注意到在同一個 CGroup 裡面,有兩個 python process (7553, 65483),
這兩隻是我們的 CLI 叫起來的 daemon:
root@localhost ~ # systemctl status main main.service - main Loaded: loaded (/etc/systemd/system/main.service; enabled) Active: active (running) since Tue 2016-01-05 13:08:54 CST; 7min ago Main PID: 5701 (main.py) CGroup: /system.slice/main.service ├─ 7553 python -u -m /core/serverd └─65483 python -u -m /core/workerd
但事實上,這兩隻 python daemon 並不是 main service 的直接 child process:
root@localhost ~ # pstree -p 5701 main.py(5701)
但是當你下 systemctl stop main 時,那兩隻 python daemon 因為在同一個 cgroup 裡面,
所以都會收到 SIGTERM 導致被砍掉~
解決的方法可以有很多種,其中一個方法就是設定 systemd 在停 main 這個 service 時,
就只要停 main process,不要送 signal 給同樣 cgroup 的其他 process~
這種做法就是讓 main process 收到 SIGTERM 之後,可以做一些 graceful shutdown,
像是將背景的 daemon 正常的結束之類的~
先找到 service 的設定檔,本例中是 /etc/systemd/system/main.service:
[Unit] Description=main [Service] Type=simple Restart=always PIDFile=/var/run/main.pid ExecStart=/main.py KillMode=process [Install] WantedBy=multi-user.target
在 [Service] 區塊加上 KillMode=process,就能在停 service 時只送 SIGTERM 給主要的 process 了~
可以用的值還有:
– control-group: 這是預設值,所有在同一個 cgroup 的 process 都會收到 SIGTERM
– process: 只有主要的 process 會收到 SIGTERM
– mixed: 主要的 process 會收到 SIGTERM,其他在同一個 cgroup 的 process 會收到 SIGKILL
– none: 不送任何的 signal
參考資料:
stackoverflow: Can’t detach child process when main process is started from systemd
systemd.kill — Process killing procedure configuration