Use lock syncronize on transaction rollback #73
Merged
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.
We are getting intermittent failures in our code base (Rails 6.1.4 on Postgres) where occasionally database cleaner tries to rollback when there are no active transactions on the connection, resulting in the following exception:
I think I have narrowed this down to a thread related race condition. We have other threads running in our test suite (
ActionCable
) which occasionally create transactions on a connection while database cleaner is cleaning up from a spec.I think this is due to a race in this code:
database_cleaner-active_record/lib/database_cleaner/active_record/transaction.rb
Lines 14 to 19 in c55d0ea
Where the transaction count is > 0 at the time line 16 executes, but by the time the code down in ActiveRecord gets called ...
https://github.com/rails/rails/blob/cf82c9d7826aa36f2481114961af02dbf39896dd/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L308-L314
... the transaction from the other thread has completed and there are no longer any transactions on the connection.
The following standalone spec can reliably reproduce the issue for me (you'll need a local PG database called
threadtest
):I don't know what the potential side effects might be, but wrapping the block in database cleaner in the same
lock.synchronize
causes the spec above to pass.