Skip to content

fix(client): enforce transaction state guard on timeout rollback to guarantee atomicity - #29769

Open
namdamdoi68-oss wants to merge 1 commit into
prisma:v7from
namdamdoi68-oss:fix/tx-timeout-atomicity-guard
Open

namdamdoi68-oss wants to merge 1 commit into
prisma:v7from
namdamdoi68-oss:fix/tx-timeout-atomicity-guard

Conversation

@namdamdoi68-oss

@namdamdoi68-oss namdamdoi68-oss commented Jul 23, 2026 •

Copy link
Copy Markdown

Enforce transaction execution state guard and serialize adapter dispatch queue in bindTransaction to prevent post-rollback query dispatch during timeout events.

Closes #29762

@CLAassistant

CLAassistant commented Jul 23, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

bindTransaction now serializes transaction operations, rejects raw query and savepoint calls after closure, and marks transactions closed before commit or rollback. The request handler also documents the timeout rollback guard that rejects query dispatch after rollback.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code adds a closed-state guard and serialized dispatch that block delayed statements after timeout rollback, satisfying #29762.
Out of Scope Changes check ✅ Passed The changes stay focused on transaction timeout handling; the only extra edit is a harmless inline comment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: enforcing transaction state guards during timeout rollback to preserve atomicity.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/driver-adapter-utils/src/binder.ts`:
- Around line 116-130: Serialize transaction finalization with adapter dispatch
around checkClosed, markClosed, and `#closeTransaction`: allow the internal
COMMIT/ROLLBACK executeRaw flow to complete, but reject or roll back user
statements once finalization begins, including statements that passed
checkClosed before dispatch was delayed. Ensure transaction closure state is
coordinated at adapter dispatch rather than only when transaction.commit() or
transaction.rollback() invokes markClosed().
- Around line 138-141: Update the transaction binder alongside queryRaw,
executeRaw, commit, and rollback to wrap createSavepoint, rollbackToSavepoint,
and releaseSavepoint with checkClosed before wrapAsync. Preserve their existing
operation behavior while ensuring each savepoint method rejects calls after the
transaction is closed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 75267d7c-7be8-45ad-b5f4-5bc9d5055a5d

📥 Commits

Reviewing files that changed from the base of the PR and between f3f5c6c and 4fc38fb.

📒 Files selected for processing (1)
  • packages/driver-adapter-utils/src/binder.ts

Comment thread packages/driver-adapter-utils/src/binder.ts Outdated
Comment thread packages/driver-adapter-utils/src/binder.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/driver-adapter-utils/src/binder.ts (1)

116-141: 🗄️ Data Integrity & Integration | 🟠 Major

The closure guard still does not serialize in-flight dispatch.

A query can pass checkClosed() while isClosed is false, then be delayed before adapter dispatch. rollback() sets isClosed = true and sends the rollback concurrently, but the previously admitted query is not cancelled or ordered behind that rollback. It can therefore execute after rollback and persist writes despite the client receiving P2028.

Coordinate closure with the adapter dispatch queue/barrier so rollback or commit excludes all pending user statements, not only calls that begin afterward.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/driver-adapter-utils/src/binder.ts` around lines 116 - 141, The
transaction wrappers around checkClosed, markClosed, queryRaw, and executeRaw
must serialize in-flight dispatch with commit/rollback. Replace the
isClosed-only guard with an adapter dispatch queue or barrier that admits
statements in order, prevents commit/rollback from running until previously
admitted statements finish, and rejects statements arriving after closure;
ensure closure is set atomically with the barrier so no pending query can
dispatch after commit or rollback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/driver-adapter-utils/src/binder.ts`:
- Around line 116-141: The transaction wrappers around checkClosed, markClosed,
queryRaw, and executeRaw must serialize in-flight dispatch with commit/rollback.
Replace the isClosed-only guard with an adapter dispatch queue or barrier that
admits statements in order, prevents commit/rollback from running until
previously admitted statements finish, and rejects statements arriving after
closure; ensure closure is set atomically with the barrier so no pending query
can dispatch after commit or rollback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 108e0780-09ab-457e-a881-cdb7a3f06cfd

📥 Commits

Reviewing files that changed from the base of the PR and between 4fc38fb and 86a5bf2.

📒 Files selected for processing (1)
  • packages/driver-adapter-utils/src/binder.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/driver-adapter-utils/src/binder.ts`:
- Around line 121-128: Update both TransactionAlreadyClosed throws in the binder
transaction flow to include the required cause string with a stable message.
Preserve the existing kind value and ensure both the immediate check and the
dispatchQueue callback produce the same complete error payload for wrapAsync
consumers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 76868b7c-275c-4cea-ae78-1b707b4f71d0

📥 Commits

Reviewing files that changed from the base of the PR and between 86a5bf2 and 3c61bc4.

📒 Files selected for processing (1)
  • packages/driver-adapter-utils/src/binder.ts

Comment thread packages/driver-adapter-utils/src/binder.ts
@tensordreams
tensordreams changed the base branch from main to v7 July 28, 2026 08:51
…serialization

Prevent post-rollback query dispatch by guarding transaction execution state and serializing dispatch queue in bindTransaction.

Signed-off-by: namdamdoi68-oss <namdamdoi68@gmail.com>
@namdamdoi68-oss
namdamdoi68-oss force-pushed the fix/tx-timeout-atomicity-guard branch from d0894eb to 2577dcc Compare July 31, 2026 06:13
@namdamdoi68-oss

Copy link
Copy Markdown
Author

Hi @wmadden @jkomyno — PR is ready for review. All CI tests pass cleanly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

$transaction is not atomic on timeout: a statement can commit after the rollback

2 participants