如果依赖服务重启,如何重新启动服务

43

一个服务(比如bar.service)依赖于另一个服务(比如foo.service),如下所示:

bar的服务文件:

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

如果foo.service被重新启动(无论是手动还是由于错误),如何使bar.service自动重新启动?


1
你尝试在你的服务中加入'Restart=always'这行代码了吗?我猜 bar 应该会在它的依赖恢复后立即重新启动。 - ogs
4
@SnP Restart:“配置服务进程退出、被杀死或超时时是否重新启动服务”,因此,除非在foo重新启动时bar崩溃,否则这将不起作用。 - Kevin M Granger
非常有趣!感谢澄清。 - ogs
3个回答

58
你可以使用PartOf
[Unit]
After=foo.service
Requires=foo.service
PartOf=foo.service

systemd.unit 手册中:

PartOf=

配置与 Requires= 相似的依赖关系,但仅限于停止和重新启动单元。当 systemd 停止或重新启动此处所列出的单元时,该操作会传播到此单元。请注意,这是一种单向依赖关系 —— 对此单元的更改不会影响所列出的单元。


14
请注意,PartOf 仅链接重启事件,而不是停止、升级、启动事件。在这些情况下,您可能需要使用 WantedBy。有关详细信息,请参见此答案 - Rennex
1
它不链接停止事件吗? 定义中上面已经说了两次:当systemd停止或重新启动此处列出的单元时,该操作会传播到此单元 - jdizzle
@jdizzle 文档可以写任何内容,但实际行为显然是不同的。我已经尝试过了。如果 foo 明确停止,那么依赖服务会随着 foo 重新启动,但在 foo 停止后再次启动时,它并不会自动启动。因此,“PartOf”适用于 foo 的自动更新或配置更新,但不能做更多的事情。 - ygoe
@ygoe 是的,它只链接停止和重启。不是启动。为此,您需要使用“Wants”或“Requires”。 - Kevin M Granger
我认为下面@ego2dot0的回答应该被接受。BindsTo正是我所需要的。在我的情况下,我希望我的服务只在postgresql处于活动状态时才能够激活,并且BindsTo的文档中说:“使用BindsTo=依赖类型和After=一起确保一个单元可能永远不会处于活动状态,除非还有一个特定的其他单元也处于活动状态(见下文)。” - Bernhard Schussek
@BernhardSchussek,听起来这确实更适合您的用例。然而,您的用例并不是原始问题所涉及的。不过,为此创建一个新问题是完全有效的! - Kevin M Granger

9
另一个解决方案可能是使用ExecStartPost选项,在foo.service重新启动时重新启动bar.service(如果它正在运行):
# foo.service
[Service]
ExecStartPost=/bin/systemctl try-restart bar.service
Restart=on-failure
RestartSec=30s

额外的RestartRestartSec选项可确保foo.service在崩溃时自动重启,从而也重启bar.service。

第二个扩展是将相同的选项加入到bar.service中,并确保bar.service在foo.service之后启动:

# bar.service
[Unit]
After=foo.service

[Service]
Restart=on-failure
RestartSec=30s

如果发生崩溃,这将自动启动两个服务,并且当foo.service重新启动时(bar.service由于错误或手动触发而重新启动)也会重新启动。


8
我认为所需的选项是BindsTo,它可以处理不良行为。
[Unit]
Requires=postgresql.service
After=postgresql.service
BindsTo=postgresql.service

BindsTo=
Configures requirement dependencies, similar to Requires=. However, BindsTo= is stronger: in addition to the effects of Requires=, it declares that this unit will also be stopped if the unit it is bound to is stopped. This means a unit bound to another unit that suddenly enters inactive state will also be stopped. Units can suddenly and unexpectedly enter inactive state for different reasons, such as the main process of a service unit terminating, the backing device of a device unit being unplugged, or the mount point of a mount unit being unmounted without involvement of the system and service manager.
When used in conjunction with After= on the same unit, the behavior of BindsTo= becomes even stronger. In this case, the unit bound to strictly has to be in active state for this unit to also be in active state. This not only means that if a unit bound to another unit suddenly enters inactive state, but also one that is bound to another unit that gets skipped due to a failed condition check (such as ConditionPathExists=, ConditionPathIsSymbolicLink=, etc.) will be stopped if it is running. Hence, in many cases, it is best to combine BindsTo= with After=.

我的经验是使用BindsTo时,单元只会停止而不会重新启动。 但是当使用PartOf时,它既可以停止也可以重新启动。 - BrnVrn
1
然而,正如@Rennex所指出的那样,启动需要在[Install]中具有WantedBy=foo.service指令。 - BrnVrn
@BrnVm WantedBy 是另一个依赖项。您的 MyService 不是 Postgres 的依赖项,但除此之外。我不想每次启动 Postgres 时都启动 MyService。我只想在 Postgres 死亡或重新启动时重新启动 MyService。 Requires 和 After 处理与 Postgres 的依赖关系,并绑定到 MyService 的重启。 - ego2dot0
在我看来,这应该是被接受的答案。 - Bernhard Schussek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接