On a real Synology first run, `migrate` exited 1 with a bare asyncpg
TimeoutError while the postgres log showed a perfectly healthy server.
The healthcheck was `pg_isready` with no -h, so it checked the UNIX SOCKET.
During first-time initialisation the postgres image runs a temporary server
that listens on the socket only (listen_addresses=''), so pg_isready answered
and the container was marked healthy while nothing was listening on TCP yet.
Dependents then connected to postgres:5432, hung, and timed out. It only bites
on the very first start of a fresh data directory, which is exactly the run an
operator is doing when they have least idea what is wrong.
- healthcheck uses `pg_isready -h 127.0.0.1 -p 5432`, so health means TCP is
actually accepting.
- `migrate` additionally waits for the port itself (DB_WAIT_SECONDS, default
180) before running alembic. It is a one-shot with no restart policy, so a
few seconds of slow NAS disk should not fail the whole bring-up; the API and
workers already self-heal through their restart policy.
Verified with a first-time bring-up against a fresh data directory: migrate
logs "database accepting connections", applies core + all four plugin
branches, and the stack comes up serving.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nux3LCu4zP9nih4BRhPyHw