我有一个 systemd 服务,每当检测到新事件时它都会生成一个 ffmpeg 进程。即使服务重新启动,这些进程也应该存活并运行完成(因此它们会尽快分离)。
目前,我已使用以下服务单元文件对其进行设置:
[Unit]
Description=My Service
[Service]
Environment="VAR1=val1" "VAR2=val2"
Type=exec
KillMode=process
ExecStart=/path/to/service/executable
Restart=on-failure
[Install]
WantedBy=default.target
虽然这有效,但根据 systemd 在日志中的警告,它并不“正确”。
systemd[1]: Found left-over process 789794 (ffmpeg) in control group while starting unit. Ignoring.
systemd[1]: This usually indicates unclean termination of a previous run, or service implementation deficiencies.
那么,处理在 systemd 中比其父进程寿命更长的分离进程的正确方法是什么?
答案1
我建议您在另一个 systemd 单元中运行长时间运行的进程。为此,您创建第二个 systemd 单元,它是模板单元。这样您就可以使用不同的参数启动它的不同实例。通常,systemd 仅运行每个单元一次(如果您在它运行时启动它,则不会发生其他情况)。模板单元以 结尾@
,您可以使用@
.因此后面具有不同字符串的不同实例@
可以同时运行。
单元 1 旨在检测新流:
[Unit]
Description=My Service
[Service]
Environment="VAR1=val1" "VAR2=val2"
Type=exec
# KillMode=process # don't do this read the man page about it
ExecStart=/path/to/service/executable
Restart=on-failure
[Install]
WantedBy=default.target
在您的程序中/path/to/service/executable
,一旦检测到新的事件/直播流,您就可以使用直播流的名称作为实例参数启动模板服务:systemctl start [email protected]
服务文件[email protected]
可能如下所示:
[Unit]
Description=Process one live stream
[Service]
# the string "%i" is substituted by systemd with the stuff you give it after the @ in the unit name.
ExecStart=/usr/bin/ffmpeg --some-args --live-stream=%i
编辑:
如果您有很多参数,您可以将它们写入临时文件并通过以下方式在模板服务中读取它们EnvironmentFile
:
[Service]
EnvironmentFile=/my/folder/%i
ExecStart=/usr/bin/ffmpeg --some-args $ARGS_FROM_ENV_FILE
答案2
您可以对服务单元文件进行一些更改:
改成。
Type=exec
Type=simple
这表明您的服务将直接启动 ffmpeg 进程,而无需分叉或后台运行。添加
RemainAfterExit=yes
到该[Service]
部分。这告诉 systemd 即使在主进程退出后也将服务视为仍然活动。
这是更新的服务单元文件:
[Unit]
Description=My Service
[Service]
Environment="VAR1=val1" "VAR2=val2"
Type=simple
KillMode=process
ExecStart=/path/to/service/executable
Restart=on-failure
RemainAfterExit=yes
[Install]
WantedBy=default.target
systemd 将不再抱怨剩余进程。它承认 ffmpeg 进程是有意分离的,并允许它运行完成,即使服务重新启动也是如此。希望有帮助!