Skip to content

fix!: EXPOSED-1076 Preserve transaction cleanup failures - #2935

Open
Devksh930 (devksh930) wants to merge 1 commit into
JetBrains:mainfrom
devksh930:fix/exposed-1076-cleanup-failures
Open

Devksh930 (devksh930) wants to merge 1 commit into
JetBrains:mainfrom
devksh930:fix/exposed-1076-cleanup-failures

Conversation

@devksh930

@devksh930 Devksh930 (devksh930) commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Description

Summary of the change: Preserve caught transaction cleanup exceptions as suppressed exceptions on the primary failure in JDBC and R2DBC.

Detailed description:

  • Why: When execution fails and rollback or resource cleanup also fails, callers currently receive the original exception without the cleanup failures reported in EXPOSED-1076.
  • What: Attach caught cleanup exceptions to the corresponding failure in occurrence order. Keep existing retry behavior, nested transaction ownership, non-cancellable cleanup, and logging. Cleanup-only failures after a successful transaction continue to leave its result unchanged.
  • How: Pass the primary failure through the existing cleanup paths and allow R2DBC physical connection-close errors to reach their caller. Initialization and temporary metadata cleanup preserve preceding failures. Add regression coverage using real H2 and PostgreSQL connections with narrow fault injection, including a Statement.execute() publisher error and exactly-once cleanup assertions.

Compatibility: Direct R2dbcConnectionImpl.close() calls now propagate driver close failures. This also affects manually managed R2dbcTransaction.close() calls that release the underlying connection. The change is marked as breaking and documented in KDoc and Breaking-Changes.md. Public API signatures are unchanged.

Related work: #2320 already preserves connection-initialization cleanup failures with addSuppressed on the JDBC side. This change extends diagnostic preservation to transaction cleanup and builds on the cancellation-safe release path from #2843. The direct R2DBC close behavior change may also be relevant to the Spring reactive transaction manager work in #2685 and #2886; those branches are outside this PR's tested scope.

Validation:

  • On 023a6a3a7 with this patch: H2 regression tests 38 passed (JDBC 22, R2DBC transaction 13, R2DBC connection 3); root detekt and root apiCheck passed.
  • Latest-main negative control: the R2DBC publisher regression fails on unmodified 023a6a3a7 because the suppressed list is empty, and passes with the production patch.
  • Earlier validation on 0e4d81a58, before the publisher regression was added: full H2 JDBC 894 passed / 161 skipped; full H2 R2DBC 801 passed / 171 skipped; focused PostgreSQL 36 passed / 1 H2-only test skipped. These full suites and PostgreSQL results have not been refreshed on the new DAO merge.
  • Remote CI results are tracked in the PR checks; the results above are local validation.

Coroutine stacktrace recovery may independently copy exceptions. Test exception types prevent those copies to isolate Exposed's suppression behavior; this change does not modify coroutine stacktrace recovery.


Type of Change

  • Bug fix
  • New feature
  • Documentation update

Updates/remove existing public API methods:

  • Is breaking change

Affected databases (shared transaction code; local driver validation is listed above):

  • MariaDB
  • Mysql5
  • Mysql8
  • Oracle
  • Postgres
  • Redshift
  • SqlServer
  • H2
  • SQLite

Checklist

  • Unit tests are in place
  • The build is green (including the Detekt check) — local checks listed above; remote CI pending
  • All public methods affected by my PR has up to date API docs
  • Documentation for my change is up to date

Related Issues

https://youtrack.jetbrains.com/issue/EXPOSED-1076

Attach caught rollback and resource-close exceptions to the primary
transaction failure in JDBC and R2DBC, preserving cleanup order and
existing retry behavior.

Cover statement execution, retry, nested transactions, cancellation,
connection initialization, and successful-transaction cleanup with
regression tests. Document the direct-close behavior change.

BREAKING CHANGE: Direct R2dbcConnectionImpl.close() calls, and manually
managed R2dbcTransaction.close() calls that release the underlying
connection, now propagate driver close failures instead of only logging
them. Transaction helpers continue to log cleanup-only failures after a
successful transaction without changing its result.

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.

1 participant