TOMEE-4652 - roll back UserTransaction left over by a request#2849
Open
jungm wants to merge 1 commit into
Open
TOMEE-4652 - roll back UserTransaction left over by a request#2849jungm wants to merge 1 commit into
jungm wants to merge 1 commit into
Conversation
A servlet or JSP that leaves a bean managed UserTransaction incomplete leaks that transaction to the next request served on the same pooled Tomcat exec thread. Geronimo's TransactionManagerImpl keeps the thread-to-transaction association (and the per-thread transaction timeout) in ThreadLocals that are only cleared on commit()/rollback(). EJBs are wrapped by container interceptors that restore the thread state; plain servlets have no equivalent, and OpenEJBValve's finally block cleaned up only the security context. Add TransactionCleanup, invoked from the request teardown finally in OpenEJBValve (sync path) and OpenEJBSecurityListener.asyncExit() (async complete/error/timeout). It rolls back and unassociates any dangling transaction and resets the per-thread transaction timeout, which leaks the same way. Also make CoreUserTransaction.resetError(null) remove() the ThreadLocal instead of set(null) so pooled threads don't keep an empty entry pinned. Adds UserTransactionLeakTest, which forces two sequential requests onto one exec thread (maxThreads=1) and asserts the second sees no leaked transaction.
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.
TOMEE-4652
A servlet or JSP that leaves a bean-managed
UserTransactionincomplete leaks that transaction to the next request served on the same pooled Tomcat exec thread. The victim request then sees a bogus transaction status — either missing an expectedIllegalStateExceptionor getting aNotSupportedException: Nested Transactions are not supportedon its ownbegin(). Which tests fail depends on which request lands on which thread, which is why the Transactions 2.0 TCK web vehicles (servlet + JSP) fail non-deterministically.Root cause
Geronimo's
TransactionManagerImplkeeps the thread-to-transaction association (and the per-thread transaction timeout) inThreadLocals that are only cleared bycommit()/rollback(). EJBs are wrapped by container interceptors that restore the thread state at the end of the call; plain servlets have no equivalent, andOpenEJBValve's request-teardownfinallyblock cleaned up only the security context. Since Tomcat pools its worker threads, the association survives into the next request.Fix
TransactionCleanup(new) — rolls back and unassociates any transaction still active on the thread at request end, and resets the per-thread transaction timeout (which leaks the same way, since Geronimo only clears it insidebegin()). If the rollback itself fails it falls back tosuspend()so the association never survives the request.finallyinOpenEJBValve(sync path) andOpenEJBSecurityListener.asyncExit()(async complete/error/timeout).CoreUserTransaction.resetError(null)nowremove()s theERRORThreadLocal instead ofset(null), so pooled threads don't keep an empty entry pinned. Separate hygiene issue, not the TCK cause.Testing
UserTransactionLeakTestforces two sequential requests onto a single exec thread (maxThreads=1) and asserts both actually shared the thread (so it can't pass vacuously), that the second request seesSTATUS_NO_TRANSACTION, and that it can still run a transaction of its own.Verified red/green: with the cleanup call removed the test fails with
expected:<[STATUS_NO_TRANSACTION]> but was:<[leaked status 0]>and a follow-upNotSupportedException: Nested Transactions are not supported— matching the issue exactly; with the fix it passes.tomee-catalinaandtomee-embeddedsuites are green.Notes for reviewers
runner-standalone/exclusions/transactions.txtin theapache/tomee-tckharness and rerun the 49-test baseline.maininStatefulBeanManagedTest,InterfaceTransactionTest, andTransactionPropagationTest(confirmed identical on a clean checkout).🤖 Generated with Claude Code