我有一個 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,Distro 是 NixOS 22.11
答案1
systemd 「啟動完成」是什麼意思?man systemd.unit
說
對於服務單元,當所有配置的啟動命令都已被呼叫並且它們失敗或報告啟動成功時,出於 Before=/After= 的目的,啟動被視為已完成。
因此,您需要查看 postgresql 服務文件,看看它是否正在執行諸如 fork 並將其 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=
,在這種情況下,列出的單元將在配置了這些選項的單元之前啟動。
(重點由海報添加)