我有一个 PostgreSQL 服务器(postgresql.service
)和一个基本的 shell 脚本(mobilizon-postgresql.service
运行该脚本是为了向第三个服务(Mobilizon)提供有关数据库的一些断言)。
因此很自然地,mobilizon-postgresql.service
配置了以下After=
依赖项postgresql.service
:
# systemctl show mobilizon-postgresql.service | grep After=
After=basic.target system.slice systemd-journald.socket sysinit.target postgresql.service
虽然重新配置系统之后(没有触及这些依赖关系),但我在日志中看到以下行为:
1677672119.103035 myserver systemd[1]: Starting Mobilizon PostgreSQL setup...
...
1677672119.153192 myserver systemd[1]: Starting PostgreSQL Server...
那么,mobilizon-postgresql.service
开始了前的启动postgresql.service
。
1677672119.279742 myserver mobilizon-postgresql-start[329444]: psql: error: could not connect to server: No such file or directory
1677672119.279742 myserver mobilizon-postgresql-start[329444]: Is the server running locally and accepting
1677672119.279742 myserver mobilizon-postgresql-start[329444]: connections on Unix domain socket "/run/postgresql/.s.PGSQL.543>
1677672119.283558 myserver systemd[1]: mobilizon-postgresql.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
1677672119.283707 myserver systemd[1]: mobilizon-postgresql.service: Failed with result 'exit-code'.
1677672119.289678 myserver systemd[1]: Failed to start Mobilizon PostgreSQL setup.
因此当然mobilizon.postgresql
无法建立与数据库的连接。
1677672119.503881 myserver postgres[329458]: [329458] LOG: starting PostgreSQL 13.10 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11>
1677672119.512541 myserver postgres[329458]: [329458] LOG: listening on IPv4 address "0.0.0.0", port 5432
1677672119.512863 myserver postgres[329458]: [329458] LOG: listening on IPv6 address "::", port 5432
1677672119.519498 myserver postgres[329458]: [329458] LOG: listening on Unix socket "/run/postgresql/.s.PGSQL.5432"
...
1677672119.871989 myserver systemd[1]: Started PostgreSQL Server.
后来才有postgresql.service
报道称该项目已全面启动。
这种行为完全违背了我对的理解After=
。来自systemd.unit(5)
:
如果单元 foo.service 包含设置 Before=bar.service 且两个单元都在启动,则 bar.service 的启动将延迟,直到 foo.service 完成启动。
我在这儿有错误的假设吗?
Systemd 版本为 251.12,发行版为 NixOS 22.11
答案1
man systemd.unit
systemd 所说的“启动完成”是什么意思?
对于服务单元来说,当所有配置的启动命令都已调用,并且它们失败或报告启动成功时,即认为服务单元的启动已完成,以 Before=/After= 为目的。
因此,您需要查看 postgresql 服务文件,看看它是否正在执行诸如分叉并将其 pid 放入文件中之类的操作,或者sd_notify()
在其代码中使用来发出“就绪”信号。这没什么用。
遗憾的是,解决这个问题的简单方法是让服务mobilizon-postgresql
等待 Unix 域套接字存在,使用inotifywait
或类似方法,或者添加Restart=on-failure
并重RestartSec=1
试直到成功。
Systemd 的工作方式是创建一个套接字单元,每当有人尝试打开该套接字时,您都会启动一个程序。在本例中,通过启动打开套接字的脚本,它会启动 postgresql。
答案2
(顺便说一句,显示完整的单位会很有帮助)
After=
不带Wants=
或Requires=
没有达到您认为的效果。如man systemd.unit
所述(关于Before=, After=
):
注意这些设置与需求依赖关系独立且正交
Requires=
由、Wants=
、Requisite=
或进行配置。在和选项BindsTo=
中同时包含单元名称是一种常见模式,在这种情况下,列出的单元将在使用这些选项配置的单元之前启动。After=
Wants=
(海报重点标注)