运行产生长时间运行的独立进程的 systemd 服务的“正确”方法是什么?

运行产生长时间运行的独立进程的 systemd 服务的“正确”方法是什么?

我有一个 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

您可以对服务单元文件进行一些更改:

  1. 改成。Type=execType=simple这表明您的服务将直接启动 ffmpeg 进程,而无需分叉或后台运行。

  2. 添加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 进程是有意分离的,并允许它运行完成,即使服务重新启动也是如此。希望有帮助!

相关内容