Rollback a managed transaction without throwing an exception
Currently it's impossible to rollback a managed transaction without raising an exception. This makes it fairly convoluted to implement logic where rollbacks are the "expected" case.
For example, I want to wrap my test cases inside a transaction that will unconditionally rollback when each one completes.
The obvious implementation is:
sequelize.transaction(txn => {
try {
return await testcase()
} finally {
txn.rollback()
}
})
But this doesn't work, because sequelize.transaction(…) unconditionally tries to commit the transaction, even if it has already been committed or rolled back.
The other obvious implementation is:
sequelize.transaction().then(txn => {
return testcase.finally(_ => txn.rollback())
})
But this doesn't work because un-managed transactions created by sequelize.transaction() don't use CLS.
I believe the fix could be as simple as changing the implementation of sequelize.transaction(…) from this:
return transaction.prepareEnvironment()
.then(() => autoCallback(transaction))
.tap(() => transaction.commit())
…
To this:
return transaction.prepareEnvironment()
.then(() => autoCallback(transaction))
.tap(() => if (!transaction.finished) transaction.commit())
…
Why dont you use unmanaged transactions, which expose t.commit / t.rollback to achieve finer control.
Managed transaction are designed in this way; do something, if you wish to rollback throw an error. For micro management, use "unmanaged" transaction
Because there's no way to use CLS with unmanaged transactions (it seems to be explicitly impossible; see also: https://github.com/sequelize/sequelize/issues/9082 )
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment 🙂
I see that with the latest version of Sequlize, the docs do reflect now that CLS does not work with unmanaged transactions https://sequelize.org/docs/v7/querying/transactions/#unmanaged-transactions
With this being the case though, how can we make use of managed transactions to share transaction without throwing an error to result in a rollback? The use case for this is in the unit tests that you write. I don't want to pass the transaction along to every query that my unit test does, but I don't want the data to be persisted after a fail or successful test.
Can someone please advice?