Binary upgrade no longer carries migrated client fds into the next generation
3.10.6 fixes the remaining fd leak in SIGUSR2 binary upgrade. Client fds
received over the migration socket are now marked close-on-exec in the new
process. A chained binary upgrade could previously inherit stale copies of
already-migrated client sockets; under load, every new generation could start
with extra fds and eventually fail with Too many open files.
The foreground upgrade path also marks inherited service fds close-on-exec
after startup and closes unexpected inherited descriptors before config load
when the process starts as a binary-upgrade child. This lets an upgraded binary
recover from a parent that was already polluted by older non-CLOEXEC fds,
instead of preserving those fds across every later generation.
Local fd exhaustion is preserved through fallback handling
3.10.5 already taught the accept and upgrade paths to treat EMFILE/ENFILE
as local fd pressure. 3.10.6 fixes the remaining fallback bug: that typed local
resource error could be lost during stale-whitelist retry or fallback error
aggregation and come back as a generic backend connectivity failure.
pg_doorman now preserves local fd exhaustion through fallback handling. The
error is not used as a PostgreSQL health signal, does not put a candidate into
cooldown, and does not trigger another Patroni discovery round when switching
nodes cannot help.
Web admin sockets use the safe TCP policy
Accepted Web UI and /metrics TCP sockets now receive the low-risk TCP
keepalive, buffer-size, and user-timeout configuration, but do not inherit the
pooler client SO_LINGER policy. This avoids abortive HTTP closes when
general.tcp_so_linger = 0 while still bounding web socket resource usage.
The web accept loop also treats EMFILE/ENFILE as local fd exhaustion and
backs off with rate-limited logging, matching the pooler listener behavior.
Upgrade notes
No config changes are required. This release is recommended for installations
that use SIGUSR2 binary upgrade, especially when upgrading from 3.9.1-3.10.5
on hosts with high client counts or tight LimitNOFILE.
Full changelog: https://ozontech.github.io/pg_doorman/changelog.html
Обновление бинаря больше не передаёт клиентские fd следующему процессу
3.10.6 закрывает оставшуюся утечку fd при обновлении по SIGUSR2. Клиентские fd, полученные через сокет миграции, теперь сразу помечаются close-on-exec в новом процессе. Раньше при нескольких обновлениях подряд новый процесс мог унаследовать лишние копии уже перенесённых клиентских сокетов. Под нагрузкой эти копии накапливались, и очередной процесс упирался в Too many open files.
При обновлении без daemon mode новый процесс после старта помечает служебные fd как close-on-exec. Дочерний процесс при таком обновлении до чтения конфига закрывает все лишние унаследованные дескрипторы. Поэтому новый бинарь может подняться даже после старого процесса, который уже накопил non-CLOEXEC fd, и не передаёт эти дескрипторы дальше.
Исправлена обработка локальной нехватки fd при выборе резервного узла
В 3.10.5 pg_doorman уже начал отличать EMFILE/ENFILE от недоступности PostgreSQL в accept loop и при обновлении бинаря. В 3.10.6 исправлена оставшаяся ошибка в fallback-пути: при повторе после устаревшего whitelist или при сборе ошибок по кандидатам локальная нехватка fd могла потерять свой тип и вернуться как обычная ошибка подключения к PostgreSQL.
Теперь pg_doorman сохраняет эту ошибку как локальную нехватку fd. Она не считается признаком неисправного PostgreSQL: кандидат не помечается временно неисправным, список сохранённых кандидатов не сбрасывается, и pg_doorman не запускает повторный поиск через Patroni там, где смена узла всё равно не поможет.
Web UI и /metrics используют отдельные TCP-настройки
TCP-сокеты web-части теперь получают keepalive, ограничение размера буферов и TCP_USER_TIMEOUT. При этом на них не применяется клиентский SO_LINGER, настроенный для соединений пулера. Поэтому general.tcp_so_linger = 0 не превращает обычное закрытие HTTP-соединения в сброс TCP-соединения. Лимиты на ресурсы при этом остаются.
Если приём web-соединения упирается в EMFILE/ENFILE, pg_doorman делает короткую паузу и ограничивает частоту сообщений в лог — так же, как основной слушатель.
Замечания по апгрейду
Менять конфиг не нужно. Обновление особенно важно для инсталляций, где используется обновление бинаря по SIGUSR2: при переходе с 3.9.1–3.10.5, на хостах с большим числом клиентов или с жёстким LimitNOFILE.
Полная история изменений: https://ozontech.github.io/pg_doorman/changelog.html