Commits
Tarun Sukhani authored defa2748e06
fix(jpa): restore wrapper-active semantics for isInsideTransaction (PF-109)
PF-106 changed isInsideTransaction(name) so it returns false for an
unmaterialized placeholder. The condition (`entityManager != null`)
was unchanged; PF-106 just stopped setting the EM eagerly. Pre-PF-106
the EM was always non-null inside withTransaction, so the check
effectively answered "is a withTransaction wrapper active for this
name on this thread?" — and downstream nesting-aware callers grew
to rely on that contract.
The most common such caller is the Tx.run pattern (run inline if
already in a tx, else open a fresh one). With PF-106 in place,
Tx.run inside an outer withTransaction whose placeholder hasn't
materialized yet sees `isInsideTransaction() == false` and starts a
NESTED withTransaction. That inner wrapper's cleanup calls
JPA.clearContext("default") — which wipes the OUTER placeholder out
of the per-thread map. The next JPA.em("default") on the outer side
throws "No active EntityManager".
Restore the wrapper-active meaning: isInsideTransaction(name) returns
true whenever a JPAContext exists for `name` on the current thread,
regardless of materialization. To keep PF-106's lazy-pool benefit
intact, push the "is there real work to commit/close?" check down
into closeTx/rollbackTx — both early-exit when the context is an
unmaterialized placeholder so the path never forces a wasteful
EntityManager acquisition.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>