atomikos / transactions-essentials

Development repository for next major release of
https://www.atomikos.com/Main/TransactionsEssentials
Other
462 stars 139 forks source link

Transaction timeout does not cause immediate rollback #91

Open Mobe91 opened 5 years ago

Mobe91 commented 5 years ago

When using single threaded 2PC, a transaction timeout will only produce a log message like

[Atomikos:55] WARN  2019-04-19T12:17:07.477 c.a.icatch.imp.ActiveStateHandler:24 Transaction 10.0.0.6.tm155566888891000056 has timed out and will rollback. 

Atomikos merely does a setRollbackOnly() on the transaction but does not actually force it to rollback immediately. It is then left to the connection reaper to terminate the connection occupied by the transaction. Also, the transaction reaper fails to remove any active transactions for the reaped connection, i.e. com.atomikos.icatch.imp.TransactionServiceImp#removeTransaction is not invoked. This causes the com.atomikos.icatch.imp.TransactionServiceImp#tidToTransactionMap_ to pile up transaction mappings which eventually prevents new transactions from being started because the size of com.atomikos.icatch.imp.TransactionServiceImp#tidToTransactionMap_ eventually exceeds com.atomikos.icatch.imp.TransactionServiceImp#maxNumberOfActiveTransactions_.

This kind of makes the transaction manager unusable as a whole... Feedback is appreciated.

GuyPardon commented 5 years ago

Well, it is the application's responsibility to terminate active transactions. Why is this a problem?

Mobe91 commented 5 years ago

What's the use of a timeout then? I want transactions to be actively rolled back, otherwise they continue to block database connections.

Narayana does the same (http://narayana.io/docs/project/index.html):

When a top-level transaction is created with a non-zero timeout, it is subject to being rolled back if it has not completed within the specified number of seconds. Narayana uses a separate reaper thread which monitors all locally created transactions, and forces them to roll back if their timeouts elapse. If the transaction cannot be rolled back at that point, the reaper will force it into a rollback-only state so that it will eventually be rolled back. 

Even if such behavior is not desired for whatever reason, the transaction must still be removed when the underlying connection is repead. Apparently, this is not happening at the moment.

GuyPardon commented 5 years ago

Reaping and transaction timeout are different things - I don't see why reap should remove a transaction: the application will typically get an exception and rollback on its own.

We used to rollback on timeout by default, but some XAResources don't like the rollback happening in a different thread than the application thread. We then changed it to the current behaviour to have less useless warnings because of that.

Maybe the real question is: why are your connections being reaped, and why are there pending transactions? Are you able to shed some light on that?

Thanks

Mobe91 commented 5 years ago

the application will typically get an exception and rollback on its own.

Why should the application receive an exception if everything is going well but the operations involved in the transaction just take too long?

Maybe the real question is: why are your connections being reaped, and why are there pending transactions? Are you able to shed some light on that?

The transactions are being reaped because I configured a reap timeout on the datasource level. At the time of reaping, there are pending transactions because the transactions simply run longer than the configured reap timeout - this can happen for whatever reason like high database load, IOPS limitations etc. IMHO it is legitimate for a connection to have an active transaction associated at the time it is being reaped.

GuyPardon commented 5 years ago

It looks like you are abusing reap for timeouts. Reaping is there to detect application conditions where connections are never released to the pool.

In your case, what you want is probably the queryTimeout at the level of the JDBC statements.

How are you demarcating transactions in your application? You should still configure rollback on exceptions.

Mobe91 commented 5 years ago

It looks like you are abusing reap for timeouts. Reaping is there to detect application conditions where connections are never released to the pool.

In your case, what you want is probably the queryTimeout at the level of the JDBC statements.

I am aware that this is not the intended purpose of the Atomikos reaper but currently, this is the only way to force a transaction to stop afaik. A transaction timeout cannot be substituted with a statement timeout. There may be long running transactions consisting of short lived statements that do not time out. Anyway, the reaper must account for connections that have transactions in progress and correctly clean up these transactions.

How are you demarcating transactions in your application? You should still configure rollback on exceptions.

I am using Spring's @Transactional annotation which will cause a transaction rollback when an exception is thrown. But that's actually not the point because the code executed in the transaction is fine, i.e. no exception is thrown. I just want to account for possibly malfunctioning transactions that run too long for some reason and I want such transactions to be rolled back after a specified timeout.

GuyPardon commented 5 years ago

OK well reap will close / destroy connections that are in use for too long. This should give an exception on which you can rollback. I don't see what else makes sense, since rollback should be done by the application thread.

YuriiZub commented 3 years ago

16:53:31.998][WARN ][Atomikos:4][c.a.logging.Slf4jLogger.logWarning(Slf4jLogger.java:24)]Transaction MyApp.tm160752920191300011 has timed out and will rollback.

I'm waiting so long time for saving to database and nothing happens. Does it mean that during some time without response, I have to throw an exception for rollback transaction?

YuriiZub commented 3 years ago

In my case were bad demarcations of transactions. It came to blocking of tables in sql server and crushing of Jms broker. (see queues in sql server)

Thanks for GuyPardon about comment on 25 Apr 2019. and Mobe91 what raised this subject here.