我有一个工作的服务,只有在运行之后才工作,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.target
并After=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
情况下进行交互的示例:Before
After
$ 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.service
ExecStartPre
active (running)
与服务不同,目标不会进入“启动”状态。相反,他们被“达成”了。让我们尝试使用 和 进行同样的操作early.target
,late.service
但late.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 服务自动运行,那么这是您在此过程中犯下的错误;像这样的事情不会是时间问题。然后采取步骤调整Before
或Requires
一次调整一个步骤,直到它停止工作。
我的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]
部分中!