-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Database reconnecting logic broken when using DB::purge() #53692
Comments
Seems like the reconnector logic has been the same for 10 years since it was originally added in 143f7a9 Going over the code a bit more, my understanding of how the reconnector logic makes sense currently is:
My best guess would be that the reconnecting logic works fine if you only use a single However if you use With that, I think it makes sense that the logic not working with |
I've removed a section with some concerns from the original post. After discovering that the reconnecting logic makes sense with |
Thank you for reporting this issue! As Laravel is an open source project, we rely on the community to help us diagnose and fix issues as it is not possible to research and fix every issue reported to us via GitHub. If possible, please make a pull request fixing the issue you have described, along with corresponding tests. All pull requests are promptly reviewed by the Laravel team. Thank you! |
Laravel Version
11.x
PHP Version
any
Database Driver & Version
irrelevant
Description
I've discovered this while debugging a very confusing scenario with parallel tests. It may be best if I start with that before getting to the root issue here. I apologize for the length/convoluted report upfront.
Essentially, if you use
CACHE_DRIVER=database
in tests, put this inAppServiceProvider::boot()
:and try to run tests with
-p
, while using cache in your tests, you will get "Call to a member function prepare() on null" aka somewhere we tried to use aConnection
instance whose$pdo
is set tonull
.The cause is that
RateLimiter
instantiatesCache\Repository
, which in the case ofCACHE_DRIVER=database
containsDatabaseStore
which then holds aConnection
instance. You can verify this by simply doingcache()->store('database');
in the service provider instead of usingRateLimiter
.So you basically get
CacheManager::$stores['database'] = DatabaseStore
with a concreteConnection
injected.This then gets invalidated by this call
framework/src/Illuminate/Testing/Concerns/TestDatabases.php
Line 53 in 8ffd13c
DB::purge()
, only when parallel tests are used.After some source diving I found that connections should be self-healing, via the
Connection::reconnect()
method. However, this logic seems to be flawed (?) because it only creates a new repaired Connection onDatabaseManager
but doesn't fix the original Connection's$pdo
.See this:
framework/src/Illuminate/Database/Connection.php
Lines 765 to 771 in 8ffd13c
framework/src/Illuminate/Database/Connection.php
Lines 1006 to 1011 in 8ffd13c
framework/src/Illuminate/Database/Connection.php
Lines 992 to 996 in 8ffd13c
With
$reconnector
being:framework/src/Illuminate/Database/DatabaseManager.php
Lines 71 to 73 in 8ffd13c
My suggestion is that
$reconnector
should look more something like this?(One caveat being that we don't deal with read/write PDO granularity here but I'm not sure if the reconnect logic does at all anyway.)
With that change, the issues described above disappear since
DatabaseStore
's$connection
gets healed by the reconnect logic.For now I've created a
draftPR #53693.Update: I've removed a section from here with some concerns, where I was worried that I may be missing the context for the current behavior. More source diving made it clear that the reconnecting logic makes perfect sense with
DB::disconnect()
but there's likely an oversight when the combination ofDB::purge()
and holding the purgedConnection
somewhere is used.Thanks for your time.
Steps To Reproduce
The text was updated successfully, but these errors were encountered: