I have a method that does heavy operations (file handling) that does not need a transaction but is inside one and generates timeouts. I don't have the option to refactor the code or to raise the default transaction timeout. I have tried using TransactionAttributeType.NOT_SUPPORTED
in the file handler method to temporarily suspend the transaction but it keeps counting time while it is suspended and keeps giving me timeout.
Is this way of working correct? When the transaction is suspended, is the transaction time still spent?
I have made the following example approximation with the same problem. Code:
@Slf4j
@Stateless
public class Foo1 {
@Inject
Foo2 foo2;
@PersistenceContext
EntityManager em;
@TransactionTimeout(value= 10, unit = TimeUnit.SECONDS)
public void saveWith10secondsTimeout() {
log.info("Start Foo1");
Foo entity = new entity();
em.persist(entity);
foo2.threadSleep15seconds();
log.info("End Foo1");
}
}
@Slf4j
@Stateless
@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
public class Foo2 {
public void threadSleep15seconds() {
log.info("Start Foo2");
try {
Thread.sleep(15 * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("End Foo2");
}
}
Controller call:
@Inject
Foo1 foo1;
@GET
@Path("/foo-not-supported")
@TransactionAttribute(TransactionAttributeType.NEVER)
public Response testNotSupported() {
log.info("Start testNotSupported");
foo1.saveWith10secondsTimeout();
return Response.status(OK).build();
}
Logs:
15:00:30,867 INFO [com.FooController] (default task-1) Start testNotSupported
15:00:30,868 INFO [com.Foo1] (default task-1) Start Foo1
15:00:30,883 INFO [com.Foo2] (default task-1) Start Foo2
15:00:40,867 INFO [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffff7f000101:-441cac6:64394e3c:382 in state RUN
15:00:40,877 INFO [org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorTrackingImpl] (Transaction Reaper Worker 0) HHH000451: Transaction afterCompletion called by a background thread; delaying afterCompletion processing until the original thread can handle it. [status=4]
15:00:40,881 INFO [com.arjuna.ats.arjuna] (Transaction Reaper Worker 0) ARJUNA012121: TransactionReaper::doCancellations worker Thread[Transaction Reaper Worker 0,5,main] successfully canceled TX 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,884 INFO [com.Foo2] (default task-1) End Foo2
15:00:45,884 INFO [com.Foo1] (default task-1) End Foo1
15:00:45,884 INFO [com.arjuna.ats.arjuna] (default task-1) ARJUNA012077: Abort called on already aborted atomic action 0:ffff7f000101:-441cac6:64394e3c:382
15:00:45,887 ERROR [org.jboss.as.ejb3.invocation] (default task-1) WFLYEJB0034: EJB Invocation failed on component Foo1 for method public void com.Foo1.saveWith10secondsTimeout(): javax.ejb.EJBTransactionRolledbackException: javax.transaction.RollbackException: WFLYEJB0447: Transaction 'Local transaction (delegate=TransactionImple < ac, BasicAction: 0:ffff7f000101:-441cac6:64394e3c:382 status: ActionStatus.ABORTED >, owner=Local transaction context for provider JBoss JTA transaction provider)' was already rolled back
The transaction timeout means that the transaction may be rolled back if it is still active when the period has elapsed. Suspending the transaction has no effect on the timeout (since that would contradict the purpose of setting the timeout).