You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: TCP keepalive for Postgres and MySQL connections
Adds `TcpKeepalive` and `net::connect_tcp_with_keepalive`, plus
`tcp_keepalive()` on `PgConnectOptions` and `MySqlConnectOptions` and
libpq-compatible URL parameters for Postgres (`keepalives`,
`keepalives_idle`, `keepalives_interval`, `keepalives_count`).
Keepalive is off by default, so nothing changes for existing users.
Motivation: without it, a connection whose server disappeared *without*
closing the socket never finds out. A failover, a killed container, or a
dropped NAT mapping leaves the client blocked reading a response that will
never arrive; there is nothing left to retransmit, so no RST is ever
provoked and the read waits forever. `TCP_NODELAY`, which is all SQLx sets
today, does not help, and a server-side `statement_timeout` cannot fire on
a server that is gone.
This is the case @abonander allowed for in
#3559 (comment):
"I suppose that's still preferable to it hanging forever on a read that
will never complete." Worth adding on the objection raised there, that a
keepalive timeout is only noticed the next time the socket is used: that
is not true of a blocked reader. When the probes are exhausted the kernel
sets `sk_err` to `ETIMEDOUT` and wakes anyone parked on the socket, so the
pending read fails rather than waiting for someone to poke it.
We hit this in production: a maintenance loop that had a query in flight
when its Postgres instance went away stopped doing work permanently, while
other loops in the same process recovered in seconds. Reproduced by holding
an `ACCESS EXCLUSIVE` lock so the query blocks server-side, then removing
the server from the network and restarting it.
Implementation follows #3559 by @xuehaonan27, rebased onto the current
`connect_tcp` and reduced to an additive API: `connect_tcp` keeps its
signature and delegates, so external drivers are unaffected.
0 commit comments