sql(postgres): release the event loop ref when a request is rejected with nothing sent
Merged
RO
2mo ago+49+49+01234567890123456789-15-15-01234567890123456789
Problem
- Regression from #34732 (73df7bb270). With
prepare: false, a script whose last query is rejected while a parameter is encoded never exits, when that query runs from a later tick than the last reply (in a timer, in a request handler). PostgresSQLQuery::do_runtakes the connection's event loop ref when it enqueues the request, then callsadvance_and_flush(). Withprepare: falsethe batch is encoded inside thatadvance(). Since #34732 a failed encode leaves nothing to send, so no reply arrives, and only the idle check at the end ofon_datareleases the ref. Before #34732 the server's close released it.
Fix
- The idle check of
on_datamoves toPostgresSQLConnection::update_poll_ref(): unref when the connection is connected, nothing is in flight and the write buffer is empty, else ref. do_runruns it withscopeguard::defer!right after it takes the ref, so every exit path after the ref recomputes it.- Verified: new test
a script whose last query was rejected exits on its owninpostgres-bind-encode-throw.test.ts. Without the fix theprepare: falsecase times out. Also thetest/js/sql/postgres-*files,sql-prepare-false,sql-pool-transaction-isolation,wire-frames,sql.test.ts: 238 tests pass.
Background
poll_refis aKeepAlive: while it is active, the process does not exit. A connection holds it only while a query is in flight, so an idle pool does not keep a script alive.- Named statements do not hit this. Their Bind is encoded from
on_data, or indo_runbefore the ref is taken.
Downsides
- Per
do_runof a prepared statement: one more idle check (4 flag and field reads). No allocation, no syscall.