Сигналы и перезагрузка

pg_doorman реагирует на четыре POSIX-сигнала: SIGHUP, SIGINT, SIGUSR2 и SIGTERM. Каждый делает одну конкретную вещь.

Краткая справка

СигналЭффектСуществующие соединенияКогда применять
SIGHUPПерезагрузить конфиг с диска.Сохраняются.Подкрутить пулы, ротировать серверные TLS-сертификаты, отредактировать pg_hba.conf.
SIGTERMНемедленное завершение.Закрываются.Остановка сервиса, когда переподключения допустимы.
SIGUSR2Горячая замена процесса: новый бинарь и конфиг, затем дренирование старого процесса.Мигрируют в новый процесс, где это возможно; TLS требует tls-migration.Раскатить изменения, которым нужен новый процесс.
SIGINTЗависит от TTY (см. ниже).По-разному.Ctrl+C при разработке; устарело для промышленной эксплуатации.

Перезагрузка (SIGHUP)

kill -HUP $(pidof pg_doorman)

Перечитывает файл конфига и применяет изменения. Что перезагружается:

  • Определения пулов (добавлены, удалены, изменён размер).
  • Списки пользователей, пароли, блоки auth_query.
  • Правила pg_hba.conf (файл или встроенное содержимое).
  • Серверные TLS-сертификаты и CA-бандлы (подмена без блокировок; существующие TLS-соединения сохраняют исходный контекст).
  • Публичные ключи Talos и JWT.
  • Уровень логирования и формат логов.

Что не перезагружается:

  • general.host, general.port — слушающий сокет фиксируется при старте.
  • general.tcp_socket_buffer_size для уже открытых сокетов — новое значение применяется только при приёме нового клиентского TCP-сокета или открытии нового TCP-сокета к PostgreSQL.
  • TLS-сертификаты для входящих клиентских подключений — нужен перезапуск процесса. Не ротируйте их во время горячей замены, где нужна миграция TLS-сессий.
  • Число рабочих потоков и параметры рантайма Tokio.

После SIGHUP SHOW CONFIG показывает новые значения. Уже открытые клиентские соединения не проверяются заново по pg_hba.conf; новые правила действуют только для новых подключений. Уже открытые TCP-сокеты сохраняют размер буфера, заданный при их создании.

Немедленное завершение (SIGTERM)

kill -TERM $(pidof pg_doorman)

pg_doorman логирует, сколько клиентов ещё в транзакциях, и выходит. Он не ждёт shutdown_timeout и не мигрирует активные транзакции. Все клиентские соединения закрываются при выходе процесса.

shutdown_timeout относится к дренированию при горячей замене процесса через SIGUSR2, а не к обычному завершению по SIGTERM.

Горячая замена процесса (SIGUSR2)

kill -USR2 $(pidof pg_doorman)

Рекомендуемый способ заменить процесс, не теряя мигрируемых клиентов:

  1. Замените бинарник и/или конфиг на диске.
  2. Отправьте SIGUSR2 работающему процессу.
  3. Текущий процесс проверяет новый бинарник с конфигом через -t.
  4. Текущий процесс порождает дочерний процесс с теми же аргументами запуска, передаёт ему слушающий сокет и продолжает обслуживать существующих клиентов до миграции или завершения.
  5. Новые клиенты сразу подключаются к дочернему процессу.
  6. Старый процесс выходит, когда клиенты мигрировали или отключились (или по shutdown_timeout).

Дочерний процесс отправляет sd_notify MAINPID=<new_pid>, чтобы юниты systemd с Type=notify корректно отслеживали новый главный PID.

Если при горячей замене изменён general.tcp_socket_buffer_size, новый процесс применяет его к мигрировавшим клиентским TCP-сокетам при восстановлении клиента. Backend-сокеты через SCM_RIGHTS не передаются: новые backend-соединения получают настройку при открытии, а старые остаются в старом процессе до дренирования.

Полный протокол, миграцию TLS и откат смотрите в горячей замене процесса с переносом сессий.

SIGINT (Ctrl+C)

SIGINT зависит от контекста:

  • На переднем плане с TTY (разработка, cargo run): только завершение работы.
  • В режиме демона или без TTY: запускает горячую замену процесса и дренирование старого процесса, как SIGUSR2, для совместимости со старыми установками.

Путь горячей замены через SIGINT существует ради обратной совместимости с инсталляциями, которые отправляют SIGINT из init-скриптов. Новые инсталляции должны явно использовать SIGUSR2 для горячей замены и SIGTERM для остановки.

Интеграция с systemd

pg_doorman поддерживает Type=notify. Поставляемый юнит pg_doorman.service запускает бинарник в основном процессе и уведомляет systemd через sd_notify:

[Service]
Type=notify
NotifyAccess=exec
ExecStart=/usr/bin/pg_doorman /etc/pg_doorman/pg_doorman.toml
ExecReload=/bin/kill -SIGUSR2 $MAINPID
ExecStop=/bin/kill -SIGTERM $MAINPID
SyslogIdentifier=pg_doorman
KillMode=mixed
TimeoutStopSec=60
Restart=on-failure
Nice=-15
User=postgres
Group=postgres
LimitNOFILE=65536

sd_notify READY=1 отправляется после привязки слушающего сокета и инициализации пулов. sd_notify MAINPID=<child> отправляется при горячей замене процесса, чтобы systemd корректно отслеживал новый процесс.

С таким юнитом systemctl reload pg_doorman означает горячую замену процесса (SIGUSR2), а не перечитывание конфига (SIGHUP). Если нужно только перечитать конфиг, используйте kill -HUP <pid>.

Если переходите с Type=forking + --daemon, уберите --daemon и переключитесь на Type=notify — меньше движущихся частей и корректное отслеживание готовности. Старые инсталляции с --daemon продолжают работать, но не получают преимуществ sd_notify.

Режим демона

pg_doorman --daemon ответвляется в фон и пишет PID в daemon_pid_file (по умолчанию /tmp/pg_doorman.pid). Под systemd предпочитайте Type=notify вместо --daemon.

general:
  daemon_pid_file: "/var/run/pg_doorman.pid"

Куда дальше