从systemd.unit(5),该选项Requires=意味着:
配置对其他单元的需求依赖。如果该单位被激活,此处列出的单位也将被激活。如果其他单元之一被停用或激活失败,则该单元将被停用。
我对此做了一个小实验。我创建了 2 个服务:a.service和b.service:
# cat a.service
[Service]
ExecStart=/bin/false
# cat b.service
[Unit]
Requires=a.service
[Service]
ExecStart=/bin/sleep 1000
Run Code Online (Sandbox Code Playgroud)
我做了之后
systemctl start b.service
我期望看到双方a.service和b.service失败,因为a.service失败/bin/false和b.service失败,a.service失败。
但是,b.service正在运行:
root@john-ubuntu:/etc/systemd/system# systemctl status a.service b.service
? a.service
Loaded: loaded (/etc/systemd/system/a.service; static; vendor preset: enabled)
Active: failed (Result: exit-code) since Thu 2017-09-07 16:38:39 CST; 2s ago
Process: 1245 ExecStart=/bin/false (code=exited, status=1/FAILURE)
Main PID: 1245 (code=exited, status=1/FAILURE)
Sep 07 16:38:39 john-ubuntu systemd[1]: Started a.service.
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Main process exited, code=exited, status=1/FAILURE
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Unit entered failed state.
Sep 07 16:38:39 john-ubuntu systemd[1]: a.service: Failed with result 'exit-code'.
? b.service
Loaded: loaded (/etc/systemd/system/b.service; static; vendor preset: enabled)
Active: active (running) since Thu 2017-09-07 16:38:39 CST; 2s ago
Main PID: 1244 (sleep)
Tasks: 1
Memory: 88.0K
CPU: 696us
CGroup: /system.slice/b.service
??1244 /bin/sleep 1000
Sep 07 16:38:39 john-ubuntu systemd[1]: Started b.service.
Run Code Online (Sandbox Code Playgroud)
我错过了什么?谢谢。
这很棘手。需要理解的主要一点是,systemd 会并行启动所有事情,除非被告知不要这样做。这实际上在手册页的“要求”部分中有说明:
需求依赖性不影响服务启动或停止的顺序
你想要实现的是“在启动b.service之前等待a.service启动”。为此,您需要在 b.service 文件中添加“Requires”和“After”选项:
[Unit]
Requires=a.service
After=a.service
[Service]
ExecStart=/bin/sleep 1000
Run Code Online (Sandbox Code Playgroud)
= 更新 =
好的,我明白出了什么问题:在 a.service 文件中,您放置了 ExecStart 命令,但没有指定类型。这意味着类型将默认为“简单”。您需要“分叉”类型才能使其工作。来自 systemd.service 手册页:
如果设置为 simple(如果既没有指定 Type= 也没有指定 BusName=,但指定了 ExecStart=,则为默认值),则预计使用 ExecStart= 配置的进程是服务的主进程。在此模式下,如果进程向系统上的其他进程提供功能,则应在守护进程启动之前安装其通信通道(例如,由 systemd 通过套接字激活设置套接字),因为systemd 将立即开始后续操作单位。
如果设置为 forking,则预计使用 ExecStart= 配置的进程将调用 fork() 作为其启动的一部分。当启动完成并且所有通信通道都建立后,父进程预计将退出。子进程继续作为主守护进程运行。这是传统 UNIX 守护程序的行为。如果使用此设置,建议同时使用 PIDFile= 选项,以便 systemd 可以识别守护进程的主进程。 一旦父进程退出,systemd 将继续启动后续单元。
因此,您应该更新 a.service 文件以包含“Type=Forking”:
[Service]
Type=forking
ExecStart=/bin/false
Run Code Online (Sandbox Code Playgroud)
这会起作用。:)