Repository navigation
sql(postgres): stop sending a Flush after a simple Query #44784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3389d68
9443177
96a1e68
0470e79
f0a9e06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -495,12 +495,8 @@ pub(crate) fn execute_query<Context: WriterContext>( | |
| query: &[u8], | ||
| mut writer: protocol::NewWriter<Context>, | ||
| ) -> Result<(), AnyPostgresError> { | ||
| // A simple Query ('Q') is its own sync point: the backend always answers it | ||
| // with exactly one ReadyForQuery. Do not append a Sync here: it would elicit | ||
| // a second, unaccounted ReadyForQuery that re-arms advance() mid-prepare. | ||
| protocol::write_query(query, &mut writer)?; | ||
| writer.write(&protocol::FLUSH)?; | ||
| Ok(()) | ||
| // Query alone: a Sync elicits a second ReadyForQuery, a Flush stops the server's idle timers. | ||
| protocol::write_query(query, &mut writer) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 After merging, a transaction idle past idle_in_transaction_session_timeout can have its next tx.unsafe()/tx.file() statement silently run on a fresh pool connection, outside any transaction and auto-committed. The server now ends the session after any simple statement (this is the change's purpose), but transaction_sql.unsafe at src/js/bun/sql.ts:696 and .file at :699 have no closed-state check, unlike transaction_sql at :679-684. Fix: before or with this change, make tx.unsafe, tx.file, reserved.unsafe and reserved.file reject with pool.connectionClosedError() once ReservedConnectionState.closed is set, so no statement bound to a dead transaction runs on a re-dialed slot. The PR text calls this a dependency on #43249; nothing in this PR enforces that ordering. Why this was flaggedA caller runs sql.begin(async tx => { await tx.unsafe("BEGIN-ish work"); await slowStep(); await tx.unsafe("UPDATE accounts ..."); }) against a server with idle_in_transaction_session_timeout set, and slowStep() takes longer than the limit. On the base branch execute_query at src/sql_jsc/postgres/PostgresRequest.rs:499 wrote a Flush behind the Query, the server read it and stopped the idle timer, so the UPDATE ran inside the transaction. After this diff only the Query is written, the server ends the backend, onTransactionDisconnected at src/js/bun/sql.ts:261 sets ReservedConnectionState.closed, and the pool re-dials the slot. transaction_sql.unsafe at src/js/bun/sql.ts:696 and transaction_sql.file at :699 call unsafeQueryFromTransaction without checking state.connectionState, so the UPDATE is sent on the new connection with no BEGIN and auto-commits, while the tagged form at :679-684 would have rejected with pool.connectionClosedError(). The PR description says #43249 must land in the same release, but this PR contains no such check. Verification: The PR description says "Needs #43249 in the same release"; that follow-up is not in this checkout (src/js/bun/sql.ts is untouched by the diff). src/sql_jsc/postgres/PostgresRequest.rs:498-499 now writes only write_query (the Flush removed). src/js/bun/sql.ts:696-705 transaction_sql.unsafe and transaction_sql.file have no ReservedConnectionState.closed check, unlike transaction_sql at :679-684.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed on the hazard, and the numbers match: on main the statement runs on the pool's next connection in 20 of 20 runs after a tagged last statement, and with this change in 40 of 40 runs after any last statement. The check is not in this PR on purpose. #43249 already adds it to You are right that nothing in the tree enforces the order. The first Downsides bullet and the status comment now say "Merge #43249 first". If a maintainer prefers one atomic PR, the helpers of #43249 can move here. |
||
| } | ||
|
|
||
| pub(crate) fn on_data<Context: ReaderContext>( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.