You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Each instance of the DatabaseCleaner::ActiveRecord::Truncation strategy initializes its @connection field only once, using the ActiveRecord default connection. When the connection is first requested, ActiveRecord checks it out of the connection pool. Various hooks (e.g. ActiveRecord::TestFixtures.teardown_fixtures) can return the connection to the pool, but Truncation is unaware of this and holds onto the connection object.
If another thread checks the same connection out of the pool and calls disconnect!, then when Truncation tries to use the connection to clean the database, it will find that the connection is closed and raise an error.
Steps to reproduce:
In a Rails/PostgreSQL project using RSpec, configure DatabaseCleaner as follows:
Summary
Each instance of the
DatabaseCleaner::ActiveRecord::Truncationstrategy initializes its@connectionfield only once, using the ActiveRecord default connection. When the connection is first requested, ActiveRecord checks it out of the connection pool. Various hooks (e.g.ActiveRecord::TestFixtures.teardown_fixtures) can return the connection to the pool, butTruncationis unaware of this and holds onto the connection object.If another thread checks the same connection out of the pool and calls
disconnect!, then whenTruncationtries to use the connection to clean the database, it will find that the connection is closed and raise an error.Steps to reproduce:
In a Rails/PostgreSQL project using RSpec, configure
DatabaseCleaneras follows:Write a test that, in a background thread, checks a connection out of the pool, removes it from the pool, and disconnects it, e.g.
(This example is obviously quite contrived; I ran into the problem in a more realistic situation. See discussion in Fix flakey async test thread error bensheldon/good_job#849.)
Expected
Actual
ActiveRecord::ConnectionNotEstablished: connection is closedraised fromDatabaseCleaner.cleaningviaTruncation#cleanWorkaround
Instead of using
DatabaseCleaner.cleaningin anaroundblock, explicitly callDatabaseCleaner.clean_with(:truncation)in anafter(:each)block:Proposed fix
Get a fresh connection in each call to
Truncation.clean-- I simulated this with a prepended module and it seems to work: