After=multi-user.target 和其他不在 systemd 服务中工作的

After=multi-user.target 和其他不在 systemd 服务中工作的

我有一个工作的服务,只有在运行之后才工作,dhcpcd.service因为它执行 github pull,并且除非 DHCP 启动,否则它无法解析主机。network.target早在 DHCP 服务完成之前就完成了。请注意,当服务应该运行时,用户michael将不会登录(它是服务器)。

问题是我无法让它运行得足够晚才能工作,而不诉诸一些超长的丑陋延迟来覆盖所有情况,例如

ExecStartPre=sleep 30

这是服务updatecontinue.service(我尝试过的多种组合之一After=):

# man systemd.service
# man systemd.unit
#
# Debug with (will print errors at the bottom, time is in UTC!):
#   -n50 to show 50 lines
#   sudo systemctl status updatecontinue
#
# Or to get a plot (open with chrome so its searchable):
#   systemd-analyze plot > ~/plot.svg

[Unit]
Description=Check if an update is halfway through, if yes, then update/enable OverlayFS/reboot

[Service]
Type=simple
ExecStart=/home/michael/.venv/terminal/bin/python3 /home/michael/terminal/script/update.py --check
After=dhcpcd.service
User=michael

[Install]
WantedBy=multi-user.target

在这里您可以看到它没有从定义的地方开始:

笔记

即使我设置为:

After=dhcpcd.service systemd-update-utmp-runlevel.service systemd-timesyncd.service

在此输入图像描述

RON建议的注意事项

systemctl get-default报告graphical.target

使用此服务:

[Unit]
Description=Check if an update is halfway through, if yes, then update/enable OverlayFS/reboot

[Service]
Type=idle
ExecStart=/home/michael/.venv/terminal/bin/python3 /home/michael/terminal/script/update.py --check
After=default.target
TimeoutStartSec=0
User=michael

[Install]
WantedBy=default.target

结果是:

在此输入图像描述

答案1

定义WantedBy=multi-user.targetAfter=multi-user.target添加了一些 systemd 试图解决的冲突。您可以在此答案的下方看到更大的解释/实验。

相反,尝试找出如果服务运行得太早就会失败的原因。After=multi-user.target运行After=该服务/目标,而不是运行。

After=network.target我的猜测是,如果您唯一的问题是网络问题,请添加。

如果您需要用户登录,请使用总线--user

如果您需要图形会话,请考虑WantedBy=graphical.target在系统总线或WantedBy=graphical-session.target用户总线上。


当你使用 时WantedBy=multi-user.target,它会给出multi-user.target一种Wants=updatecontinue.service关系。

这只是意味着:如果已启动,updatecontinue.service则将启动。multi-user.target如果updatecontinue.service启动失败,不影响multi-user.target

然后,你给出updatecontinue.service一个Requires=multi-user.target关系。这是一个重大冲突。 Requires=几乎与Wants=(如果你开始,也将启动)。除外:如果单位无法激活,装置将无法启动。

所以你实际上只有两个互相启动的单元,这可能不是你想要的。Requires=为了清楚起见,我会放弃依赖性。


Before/关系确实有效,下面是两个服务在没有/ 的After情况下进行交互的示例:BeforeAfter

$ systemctl --user cat {early,late}.service
# /home/stew/.config/systemd/user/early.service
[Unit]
Wants=late.service

[Service]
ExecStartPre=sleep 2
ExecStart=sleep 20

# /home/stew/.config/systemd/user/late.service
[Service]
ExecStart=sleep 5

$ systemctl --user start early
$ journalctl --user --since "2 minutes ago" --no-hostname
Mar 08 15:54:42 systemd[1064]: Starting early.service...
Mar 08 15:54:42 systemd[1064]: Started late.service.
Mar 08 15:54:44 systemd[1064]: Started early.service.

可以看到服务同时启动。

现在让我们尝试建立late.service一个After=early.service关系:

$ systemctl --user cat {early,late}.service
# /home/stew/.config/systemd/user/early.service
[Unit]
Wants=late.service
[Service]
ExecStartPre=sleep 2
ExecStart=sleep 20

# /home/stew/.config/systemd/user/late.service
[Unit]
After=early.service
[Service]
ExecStart=sleep 5

$ systemctl --user start early
$ journalctl --user --since "2 minutes ago" --no-hostname
Mar 08 16:01:09 systemd[1064]: Starting early.service...
Mar 08 16:01:11 systemd[1064]: Started early.service.
Mar 08 16:01:11 systemd[1064]: Started late.service.

在这种情况下,您可以看到完成late.service后已开始(等待单元变为)。early.serviceExecStartPreactive (running)


与服务不同,目标不会进入“启动”状态。相反,他们被“达成”了。让我们尝试使用 和 进行同样的操作early.targetlate.servicelate.service需要一些时间才能开始:

$ systemctl --user cat early.target late.service
# /home/stew/.config/systemd/user/early.target
[Unit]
Wants=late.service

# /home/stew/.config/systemd/user/late.service
[Service]
ExecStartPre=sleep 2
ExecStart=sleep 5

$ systemctl --user start early.target
$ journalctl --user --since "2 minutes ago" --no-hostname
Mar 08 16:07:27 systemd[1064]: Starting late.service...
Mar 08 16:07:29 systemd[1064]: Started late.service.
Mar 08 16:07:29 systemd[1064]: Reached target early.target.

early.target我们看到“到达”需要 2 秒。这意味着只有当目标的“Wants=”全部完成其“激活”阶段并进入“活动(运行)”状态时,目标才“达到”。

了解了这一点,我们现在可以理解为什么 aAfter=foo.target与 a 混合WantedBy=foo.target有点冲突了。 foo.target正在等待我们在到达之前开始。同时,我们希望foo.target在开始之前就与您取得联系。

答案2

我正在努力让服务尽可能晚地运行

After=default.target

默认目标将等于所systemctl set-default设置的值。

SysV 运行级别及其相应的 systemd 目标的完整列表是

0    runlevel0.target, poweroff.target     {Shut down and power off the system.}
1    runlevel1.target, rescue.target       {Set up a rescue shell.}
2    runlevel2.target, multi-user.target   {Set up a non-graphical multi-user system.}
3    runlevel3.target, multi-user.target   {Set up a non-graphical multi-user system.}
4    runlevel4.target, multi-user.target   {Set up a non-graphical multi-user system.}
5    runlevel5.target, graphical.target    {Set up a graphical multi-user system.}
6    runlevel6.target, reboot.target       {Shut down and reboot the system.} 

基本上要么是systemctl set-default graphical.target要么systemctl set-default multi-user.target是所有已经完成的事情。您可以systemctl get-default查看当前设置的内容。

我有一个服务,如果我手动启动它就可以工作,但它不会在启动时启动。

很容易搞乱服务文件中的语法或等价物ExecStart,这样,如果您手动运行 ExecStart 定义的脚本,它将起作用,但在 systemd 服务的条件下它将无法运行。确实需要测试和调试,我不认为这是一个“计时”问题。做一些简单的事情,比如/usr/bin/echo hello > /testfile首先确保它将手动运行,如果它确实运行但随后没有从 systemd 服务自动运行,那么这是您在此过程中犯下的错误;像这样的事情不会是时间问题。然后采取步骤调整BeforeRequires一次调整一个步骤,直到它停止工作。

我的administration.service文件/etc/systemd/system/位于

#!/bin/bash

[Unit]
Description=administration
After=default.target

[Service]
Type=idle
ExecStart=/root/scripts/administration.sh
TimeoutStartSec=0

[Install]
WantedBy=default.target

我的/root/scripts/administration.sh文件是root.root with-rwx------ and has#!/bin/bash` 在它的顶部;只要弄乱第一行,我的服务就无法运行。

请务必检查systemctl list-unit-files | grep administration需要显示为已启用 {相应地调整语法以满足您的需求}。

systemctl daemon-reload如果您的administration.service文件存在但在执行时没有显示systemctl list-unit-files

如果 /etc/systemd/system/ 是生成用户定义服务的正确位置,我会让其他人发布;我所知道的是,如果该服务是 root 拥有的,那么它对我有用,并且如果它本质上是管理员,那么它就有意义。

答案3

尝试在小睡时编码不是一个好主意,问题是,After=在该[Unit]部分中一定很愚蠢,而不是在该[Service]部分中!

相关内容