视觉智能的哲学实践:MAA如何用3种技术范式重构明日方舟自动化
2026/6/16 15:12:11
Systemd 利用 Linux 的 cgroup 机制来管理进程树:
# 查看服务的cgroupsystemctl show aservice --property=ControlGroup systemd-cgls /system.slice/aservice.service当 systemd 启动服务时:
# 默认发送 SIGTERMsystemctl stop aservice# 等同于kill-TERM<main_pid>[Service] TimeoutStopSec=90 # 默认90秒后发送SIGKILL KillMode=control-group # 默认:杀死cgroup中的所有进程[Service] # 默认值:杀死cgroup中的所有进程 KillMode=control-group # 可选值: # control-group: 杀死cgroup中所有进程(默认) # process: 只杀死主进程 # mixed: 向主进程发SIGTERM,向子进程发SIGKILL # none: 不杀死任何进程[Service] Type=simple ExecStart=/usr/bin/aservice KillMode=none问题:主进程退出后,子进程变成僵尸或继续运行但systemd认为服务已停止。
setsid或nohup[Service] Type=forking ExecStart=/usr/bin/aservice-wrapper # 包装脚本 # wrapper脚本示例 #!/bin/bash /usr/bin/nohup /usr/bin/real-daemon > /dev/null 2>&1 & # 或 /usr/bin/setsid /usr/bin/real-daemon exit 0[Service] Type=forking PIDFile=/var/run/aservice-main.pid ExecStart=/usr/bin/aservice-daemonize KillMode=process # 只杀死主进程[Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/bash -c "systemd-run --scope --unit=aservice-children.service /usr/bin/child-process"# aservice-parent.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/systemctl start aservice-children.service # aservice-children.service [Service] Type=simple ExecStart=/usr/bin/child-process# /etc/systemd/system/aservice-main.service [Unit] Description=AService Main Controller After=network.target Wants=aservice-workers.service [Service] Type=simple ExecStart=/usr/bin/aservice-controller Restart=always KillMode=process # 只杀控制器 [Install] WantedBy=multi-user.target # /etc/systemd/system/aservice-workers.service [Unit] Description=AService Workers PartOf=aservice-main.service # 主服务停止时,这个服务也会停止 BindsTo=aservice-main.service # 主服务重启时,这个服务也重启 [Service] Type=forking ExecStart=/usr/bin/aservice-worker-manager KillMode=none # 不杀工作进程[Service] Type=simple ExecStart=/bin/bash -c 'cd / && /usr/bin/setsid /usr/bin/real-daemon &' KillSignal=SIGINT SendSIGKILL=no#!/bin/bash# /usr/libexec/aservice-starter# 创建独立会话{# 脱离当前控制组execsetsid"$@"&child_pid=$!# 将子进程移出当前cgroupecho$child_pid>/sys/fs/cgroup/systemd/tasks2>/dev/null||true# 等待主进程结束wait$child_pidexit$?}&[Service] Type=oneshot ExecStart=/bin/bash -c ' # 启动子进程到独立cgroup mkdir -p /sys/fs/cgroup/systemd/independent echo $$ > /sys/fs/cgroup/systemd/independent/tasks exec /usr/bin/child-process '#!/usr/bin/env python3# signal-forwarder.pyimportosimportsignalimportsubprocessimporttimedefsignal_handler(signum,frame):# 不转发SIGTERM给子进程ifsignum==signal.SIGTERM:print("Received SIGTERM, exiting without killing children")os._exit(0)defmain():# 设置信号处理器signal.signal(signal.SIGTERM,signal_handler)# 启动子进程child=subprocess.Popen(["/usr/bin/real-daemon"])# 等待子进程或信号whileTrue:time.sleep(1)if__name__=="__main__":main()KillMode=none可能导致服务状态不准确推荐架构: ┌─────────────────┐ │ Systemd │ │ (主服务单元) │ └─────────┬───────┘ │ control-group ▼ ┌─────────────────┐ │ 控制器进程 │ ← SIGTERM │ (轻量级) │ └─────────┬───────┘ │ 通过IPC/套接字 ▼ ┌─────────────────┐ │ 工作进程池 │ ← 独立管理生命周期 │ (setsid启动) │ └─────────────────┘关键原则:
这种方法既保持了 systemd 的管理能力,又允许工作进程有独立的生命周期。