У меня есть сервер PostgreSQL ( postgresql.service
) и базовый скрипт оболочки ( 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, чтобы увидеть, делает ли он что-то вроде разветвления и помещения своего 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=
, в этом случае указанный блок будет запущен до блока, настроенного с помощью этих параметров.
(Выделено автором постера)