MODDATAIMP-1278: Fix broken RxJava transaction lifecycle in streaming methods#727
Merged
KaterynaSenchenko merged 4 commits intoApr 15, 2026
Conversation
… methods The three streaming methods (streamRecords, streamMarcRecordIds, streamSourceRecords) had multiple transaction lifecycle bugs: - doAfterTerminate(tx::commit) fired on both success AND error, issuing a commit after a rollback - conn.close() was called twice (doOnError + doFinally) - Cleanup Future return values were silently discarded Consolidate into a shared streamInTransaction() helper with a StreamContext inner class that ensures: - Commit only on successful stream completion - Rollback only on error or cancellation - Stream cursor quiesced before rollback (prevents in-flight fetch race) - Exactly-once cleanup via AtomicBoolean guard - Cancel-path errors logged instead of silently swallowed Add test that exercises 25 rapid cancel-after-first-row cycles followed by a full stream read, proving the connection pool is not exhausted.
Exercise the prepare-failure error path (invalid SQL) to cover rollbackTransactionAndClose and the outer onErrorResumeNext handlers. Runs 5 failed streams then a valid stream to verify pool is not exhausted by leaked connections on the error path.
Aliaksandr-Fedasiuk
approved these changes
Mar 24, 2026
RuslanLavrov
approved these changes
Apr 9, 2026
KaterynaSenchenko
approved these changes
Apr 10, 2026
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Purpose
Fix broken transaction lifecycle in the three streaming DAO methods (
streamRecords,streamMarcRecordIds,streamSourceRecords) that caused connection pool leaks. The old code committed after rollback on error paths, double-closed connections, and silently discarded cleanup Futures.Approach
A simple fix could look like so:
But its missing the following:
andtx.rollback()` still return Futures that are silently discarded. If commit fails, the error is lost.PreparedStatement(pq).firstOrError(),take(n)), neitherdoOnCompletenordoOnErrorfires. OnlydoFinallyfires. So the transaction is never explicitly committed or rolled back.For a full solution, consolidate the three duplicated streaming patterns into a shared
streamInTransaction()helper with aStreamContextinner class. The new lifecycle ensures: commit only on success, rollback only on error/cancel, stream cursor quiesced before rollback, exactly-once cleanup viaAtomicBooleanguard, and cancel-path errors logged instead of swallowed. Includes a test that exercises 25 rapid cancel cycles to prove the pool is not exhausted.Refs: https://folio-org.atlassian.net/browse/MODDATAIMP-1278