prosgarz35 opened a new pull request, #3237:
URL: https://github.com/apache/james-project/pull/3237
## Description
This PR provides surgical fixes for critical operational issues in the
PostgreSQL backend stack (`backends-common/postgres` and `mailbox/postgres`):
### 1. Rollback transaction on timeout (`PostgresExecutor.java`)
- **Problem**: When a reactive timeout (`jooqReactiveTimeout`) was triggered
inside `executeTransaction(...)`, `handleTimeout(connection, e)` cancelled the
running query via `cancelRunningQuery(connection)`, but omitted rolling back
the uncommitted transaction. As a result, the connection remained in an
open/in-progress transaction state (`idle in transaction`), locking table rows
and holding connections from the R2DBC pool until eviction.
- **Fix**: Added `handleTransactionTimeout(connection, timeoutException)`
which cancels the running query and explicitly rolls back the transaction
before propagating the `TimeoutException`.
### 2. Null-safe check in `preparedStatementConflictException`
(`PostgresExecutor.java`)
- **Problem**: In `preparedStatementConflictException()`, checking
`throwable.getMessage().contains(...)` without verifying `getMessage() != null`
could throw an unexpected `NullPointerException` during retry filtering if the
root cause exception lacked a message.
- **Fix**: Added null-guard check `throwable.getMessage() != null`.
### 3. Ensure connection release on error/cancel in schema management
(`PostgresTableManager.java`)
- **Problem**: `Mono.usingWhen` calls in schema initialization
(`initializePostgresExtension`, `initializeTables`, `listExistTables`,
`truncate`, `initializeTableIndexes`) only registered the normal completion
release callback (`asyncCleanup`). In the event of an error or downstream
cancellation during table or index creation, the acquired R2DBC connections
were not properly closed/returned to the pool.
- **Fix**: Configured `onError` and `onCancel` callbacks to guarantee
connection closure across all execution paths.
### 4. Protect UID and ModSeq monotonic invariants (`PostgresUidProvider`,
`PostgresModSeqProvider`, `PostgresMessageMapper`)
- **Problem**: `incrementAndGetLastUid` and `incrementAndGetModSeq` used
`.defaultIfEmpty(MessageUid.MIN_VALUE)` and `.defaultIfEmpty(ModSeq.first())`.
If a mailbox was concurrently deleted or not found, the operation silently fell
back to UID `1` or ModSeq `1`. This broke RFC 3501 strict monotonic ordering
guarantees and could corrupt client sync state.
- **Fix**: Replaced `.defaultIfEmpty(...)` fallbacks with
`.switchIfEmpty(Mono.error(new MailboxNotFoundException(...)))` across
`PostgresUidProvider`, `PostgresModSeqProvider`, and
`PostgresMessageMapper.setNewUidAndModSeq`.
---
## Testing
- Clean compilation and build verified across:
- `backends-common/postgres`
- `mailbox/postgres`
- `server/apps/postgres-app`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]