如何确保在systemd中启动服务之前有延迟?

Sir*_*mar 41 systemd

我有一个服务,依赖于Cassandra优雅地出现,集群正在准备好.

为了确保满足依赖顺序,我有以下单元文件

[Unit]
Requires=cassandra.service
After=cassandra.service

[Service]
Environment=JAVA_HOME=/usr/java/jre
ExecStart=@bringup.instance.path@/webapps/bringup-app/bin/bringup
TimeoutStartSec=0
ExecStop=
PIDFile=@bringup.instance.path@/logs/bringup.pid
Restart=always

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

如何确保启动应用程序进程在尝试启动之前等待30秒?目前虽然它是在Cassandra之后启动的,但我注意到Cassandra集群尚未启动,因此任何来自启动应用程序连接到Cassandra的尝试都会失败.

因此,我想添加一个延迟.这可能通过单位文件?

Ort*_*kni 58

您可以运行在睡眠的前命令ExecStartExecStartPre:

[Service]
ExecStartPre=/bin/sleep 30
Run Code Online (Sandbox Code Playgroud)

  • 这可能有效但对服务重启也有影响. (11认同)
  • 当使用上述方法且延迟超过 90 秒时,服务的启动超时时间必须增加(例如 `TimeoutStartSec=120`) (8认同)
  • 这对服务重启有效,这对我的用例来说是一个好处 (7认同)
  • 你怎么解决这个问题而没有在服务重启时睡不着觉? (4认同)
  • 我觉得 systemd 并不真的希望我这样做。如果延迟较长,这会导致超时,例如“systemctl start x”在睡眠完成之前不会返回 (2认同)

Zan*_*tsu 21

您可以创建一个.timersystemd单位文件来控制单位文件的执行.service

因此,例如,要在启动后等待1分钟再启动,请在与目录相同的目录中foo.service创建一个foo.timer文件:

[Timer]
OnBootSec=1min
Run Code Online (Sandbox Code Playgroud)

重要的是,要禁用所有服务(这样它就不会在启动时启动)并启用计时器,所有这些才能正常工作(这要归功于用户部落):

systemctl disable foo.service
systemctl enable foo.timer
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到许多其他选项和所需的所有信息:https : //wiki.archlinux.org/index.php/Systemd/Timers

  • IMO 这是最好的答案,因为当执行 ExecStartPre 指令时,systemd 认为一个单元正在“启动”。 (5认同)
  • 虽然这会奏效,但对于简单的延迟来说,这是一种矫枉过正。对于简单的延迟,使用 ExecStartPre 并使用计时器进行更复杂的计划。 (2认同)
  • OnBootSec 显然与盒子“首次启动”的时间相关,因此如果您尝试“之后启动”的服务没有在 1m 内启动,它仍然可能启动得太早,我想知道?https://www.freedesktop.org/software/systemd/man/systemd.timer.html 但我想如果你设置一个足够长的数字它可以工作...... (2认同)

小智 9

我已经使用 systemd 计时器来延迟服务并且效果很好

# /lib/systemd/system/foo.timer 
[Unit]
Description=Wait some second before run foo

[Timer]
OnActiveSec=5sec
AccuracySec=1s

[Install]
WantedBy=timers.target
Run Code Online (Sandbox Code Playgroud)

请参阅计时器:systemctl list-timers

日志:

journalctl -f -u foo.timer
journalctl -f -u foo
Run Code Online (Sandbox Code Playgroud)


bvi*_*tor 8

无需编辑启动服务,而是将启动后延迟添加到它所依赖的服务上。cassandra.service像这样编辑:

ExecStartPost=/bin/sleep 30
Run Code Online (Sandbox Code Playgroud)

这样,增加的睡眠不应该减慢依赖于它的启动服务的重启(尽管会减慢其自身的启动速度,也许这是合乎需要的?)。


Gra*_*Lea 8

结合@Ortomala Lokni 和@rogerdpack 的答案,另一种选择是在第一个已经开始/完成您正在等待的事情时让依赖服务监视器。

例如,下面是我如何让 fail2ban 服务等待 Docker 打开端口 443(这样fail2ban 的 iptables 条目优先于 Docker 的条目):

[Service]
ExecStartPre=/bin/bash -c '(while ! nc -z -v -w1 localhost 443 2>/dev/null; do echo "Waiting for port 443 to open..."; sleep 2; done); sleep 2'
Run Code Online (Sandbox Code Playgroud)

只需替换nc -z -v -w1 localhost 443为在第一个服务启动时失败(非零退出代码)的命令,并在启动后成功。

对于 Cassandra 情况,理想的情况是仅在集群可用时返回 0 的命令。

(也可能希望从默认的 90增加TimeoutStartSec,或设置TimeoutStartSec=0为禁用启动超时)

  • 最佳答案在这里,完全被低估了!我添加了 rogerdpack 的答案中有关增加 TimeoutStartSec 的注释,或者您可以将其设置为 0 以禁用启动超时。 (3认同)

nel*_*aro 5

我认为这个超级用户的答案是一个更好的答案. https://superuser.com/a/573761/67952

但是既然你没有使用Before和After,那么你可以使用:

Type=idle
Run Code Online (Sandbox Code Playgroud)

正如man systemd.service解释的那样

闲置行为非常类似于简单; 但是,服务程序的实际执行会延迟,直到调度所有活动作业为止.这可用于避免将shell服务的输出与控制台上的状态输出交错.请注意,此类型仅用于改进控制台输出,它不能用作常规单元排序工具,并且此服务类型的效果会受到5s超时的影响,之后无论如何都会调用服务程序.

  • 您方便地从引号中省去了最重要的部分:“此类型仅用于改善控制台输出,它不用作常规的单元订购工具,并且此服务类型的效果受到5 s超时的影响,之后无论如何都要调用服务程序,通常不建议对长时间运行的服务使用空闲或单发。 (3认同)
  • @bviktor,文档已更新。你是对的,它没有正确解释它的目的文档确实说“但是,服务程序的实际执行被延迟,直到所有活动作业都被分派”。文档接缝自相矛盾。 (2认同)

rog*_*ack 5

systemd这样做的方法是让进程在以某种方式设置时“回话”,例如通过打开套接字或发送通知(或父脚本退出)。这当然并不总是直截了当的,尤其是对于第三方的东西:|

你也许可以做一些内联的事情

ExecStart=/bin/bash -c '/bin/start_cassandra &; do_bash_loop_waiting_for_it_to_come_up_here'
Run Code Online (Sandbox Code Playgroud)

或执行相同操作的脚本。或者放入do_bash_loop_waiting_for_it_to_come_up_here一个 ExecStartPost

或者创建一个helper .service 等待它出现,所以helper 服务依赖于cassandra,并等待它出现,那么你的其他进程就可以依赖该helper 服务。

(也可能希望从默认的 90增加TimeoutStartSec