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]

Reply via email to