如何确保“一次性”服务在第一次失败时重试?

如何确保“一次性”服务在第一次失败时重试?

我已经阅读了 systemd 服务手册几次,但我仍然无法弄清楚基本的 systemd 模式:

我想在启动时运行一次启动过程(如 Docker 容器或格式化驱动器),并成功完成。但是,如果我为此使用 Type=oneshot,则无法使用 Restart=on-failure,并且如果失败,则它不会重试该作业。我在这里遗漏了一些明显的东西吗?

我还尝试使用 Restart=on-failure 设置 Type=simple ,但在很多情况下,我需要 oneshot 服务提供的以下行为(来自联机帮助页):

oneshot 的行为与 simple 类似;然而,预计该进程必须在 systemd 启动后续单元之前退出。

更新:

答案1

我正在尝试的一种可能的解决方法是

  [Unit]
    Description=Tags instance and EBS vols
    After=docker.service
    Requires=docker.service

    [Service]
    ExecStartPre=/usr/bin/docker run --rm -v /opt/tag.sh:/tag.sh -v /opt:/ack --entrypoint=/bin/sh alpine /tag.sh
    ExecStartPre=/usr/bin/sh -c '[[ -e /opt/TAG_SUCCESS ]]'
    ExecStart=/usr/bin/rm /opt/TAG_SUCCESS
    Restart=on-failure
    RestartSec=30

脚本执行结束时的tag.sh位置。touch /ack/TAG_SUCCESS我相信这非常接近所需的行为,因为ExecStartPre将按顺序执行,在调用之前等待成功完成ExecStart,并且该单元仅被考虑Starting一次ExecStart,此时我们确信我们已经完成了启动任务。

但这仍然感觉像是一个巨大的黑客攻击?

答案2

环顾四周后,我发现 systemd 的notify-type 具有oneshotexec属性组合的属性:

notify 的行为与 exec 类似;但是,预计服务在完成启动后会通过 sd_notify(3) 或等效调用发送通知消息。发送此通知消息后,systemd 将继续启动后续单元。如果使用此选项,则应设置 NotifyAccess=(见下文)以开放对 systemd 提供的通知套接字的访问。如果NotifyAccess=缺失或设置为none,则会被强制设置为main。

其中:

exec 类型与 simple 类似,但服务管理器将认为该单元在执行主服务二进制文件后立即启动。服务经理将推迟后续单元的启动,直到此时。 (或者换句话说:在 fork() 返回后,simple 会立即继续执行进一步的作业,而在服务进程中的 fork() 和 execve() 成功之前,exec 不会继续执行。)请注意,这意味着 systemctl 启动 exec 服务的命令行当服务的二进制文件无法成功调用时将报告失败(例如因为所选的 User= 不存在,或者服务二进制文件丢失)

即结合simpleoneshot行为:

# <your service>.service
[Unit]
Description=Your awesome service

[Service]
ExecStart=/usr/local/bin/your-daemon-script
Restart=on-failure
RestartSec=30
NotifyAccess=all 
# your-daemon-script
# Start everything
# ...
# If an error happens here, the service will restart
# If everything went fine systemd-notify --ready is used to notify systemd about that.
# After notifying systemd, systemd will switch the services state into ready and then starts other services which had to wait for this serivce to get ready.
systemd-notify --ready

相关内容