Deprecate master/slave terminology and underlying feature#4055
Deprecate master/slave terminology and underlying feature#4055greg0ire wants to merge 1 commit intodoctrine:2.11.xfrom
Conversation
| /** | ||
| * Connects to a specific connection. | ||
| */ | ||
| private function connectTo(string $connectionName): DriverConnection |
There was a problem hiding this comment.
If you think somebody relies on connectTo or chooseConnectionConfiguration, we could make them public. Doing so after this is merged and release would not be a BC break though.
There was a problem hiding this comment.
If somebody needs to choose the connection explicitly, they should operate those connections manually w/o this wrapper.
There was a problem hiding this comment.
Why? And who would that somebody be? This method is private, so it can't be used by somebody outside this class if that's who you were thinking.
There was a problem hiding this comment.
If you think somebody relies on
connectToorchooseConnectionConfiguration, we could make them public.
It was the answer to your comment. I don't think that this should be made part of the public API.
lib/Doctrine/DBAL/DriverManager.php
Outdated
| $params = self::parseDatabaseUrl($params); | ||
|
|
||
| // URL support for MasterSlaveConnection | ||
| // @todo: deprecated, notice thrown by connection constructor |
There was a problem hiding this comment.
Will the Connection constructor get a deprecation message in this PR?
There was a problem hiding this comment.
Ah right that's a part I forgot to backport from #4054
There was a problem hiding this comment.
Unsure about the @todo part, I copied it from #4054, is this a way we have to remember to remove things on 3.0.x?
There was a problem hiding this comment.
I don't know. I thought @deprecated and/or trigger_error() is usually in use.
755b058 to
52da3f5
Compare
Codecov Report
@@ Coverage Diff @@
## 2.11.x #4055 +/- ##
=========================================
Coverage 71.02% 71.02%
Complexity 5261 5261
=========================================
Files 217 217
Lines 13355 13358 +3
=========================================
+ Hits 9485 9488 +3
Misses 3870 3870
Continue to review full report at Codecov.
|
morozov
left a comment
There was a problem hiding this comment.
API-wise looks good. We should be able to address the implementation details issues later.
| * | ||
| * @var DriverConnection[]|null[] | ||
| */ | ||
| private $connections = ['primary' => null, 'replica' => null]; |
There was a problem hiding this comment.
As far as I understand, it's one primary and many replicas. Why do we need to keep them under one array with magic keys? It's fine if we don't resolve it in this ticket.
There was a problem hiding this comment.
I can resolve it in this ticket, I think that will be the easiest part TBH :P
There was a problem hiding this comment.
In fact it's just the one replica (picked at random), as stated in the comment above. Your comment still applies though.
| /** | ||
| * Connects to a specific connection. | ||
| */ | ||
| private function connectTo(string $connectionName): DriverConnection |
There was a problem hiding this comment.
If somebody needs to choose the connection explicitly, they should operate those connections manually w/o this wrapper.
02971b3 to
0f368ee
Compare
| } | ||
|
|
||
|
|
||
| parent::__construct($params, $driver, $config, $eventManager); |
There was a problem hiding this comment.
This is another place where my eyes are bleeding. The parent class doesn't understand the "replica" key but for some reason, we're passing it there. Shouldn't the concept of multiple connections be encapsulated to this very class?
There was a problem hiding this comment.
🤔 uh yeah that's nasty. Are you suggesting unset-ing replica and primary, storing them in some other property, or not calling the parent constructor altogether (and then maybe stop extending Connection??)
There was a problem hiding this comment.
We cannot avoid extending the connection because there's no DBAL-level connection interface to implement. Unsetting and managing the replica parameters within the class would help migrate to composition later.
|
|
||
| public function query(): Statement | ||
| { | ||
| $this->switchToPrimary(); |
There was a problem hiding this comment.
And it's even worse here. Why are we switching to the primary endpoint to execute a query?
There was a problem hiding this comment.
I won't lie, I have no idea…
There was a problem hiding this comment.
the query function can be used for any kind of SQL, including write operations. This cannot be detected without parsing the SQL statement, which is a rabbit hole. This is why for safety reason the connectoin assumes that when using $connection->query(), you might be performing a write operation.
There was a problem hiding this comment.
This is why the developer should be in control of which connection to use for a given statement. Not the abstraction layer.
|
@morozov this looks nasty too: dbal/lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php Lines 34 to 41 in 0ad4c16 |
|
|
||
| $driverOptions = $params['driverOptions'] ?? []; | ||
|
|
||
| $connectionParams = $this->chooseConnectionConfiguration($connectionName, $params); |
There was a problem hiding this comment.
So does this mean that every time we "switch" between the primary and replica endpoints, the replica will be randomly chosen and reconnected to while the old replica connection will be closed? Even if there's only one replica configured. What's the rationale behind this behavior?
There was a problem hiding this comment.
🤔 we are not supposed to switch from the primary to the replica, are we?
There was a problem hiding this comment.
This is really questionable behavior. If I insert a "user logged in" event in one table and then query a heavy report from the other, why should the report use the master connection?
There was a problem hiding this comment.
The step from primary to replica is not really a common use-case, but what you describe could be an example. If the application does a single write early in the request and you can isolate that and don't need to care about replication lag with this write, then you could switch back to a replica. The idea would be:
$connection->connect('primary');
$connection->executeUpdate("....");
$connection->connect("replica");There was a problem hiding this comment.
Why not just do $primaryConnection->executeUpdate(); $replicaConnection->doWhatever();? Why keep one connection as a shared state and switch between the inner connections implicitly?
There was a problem hiding this comment.
The answer is probably "convenience" (at the cost of some usefulness). Like always with such things ;)
|
Given the number of WTFs that this code produces, I'd personally prefer to just deprecate it for now. If we don't manage to implement a proper replacement (and given all the possible variations of the behavior, I don't think we should), the old code could be just copy/pasted in the project that needs this functionality. But looking at the behaviors that it implements, I hope nobody in their right mind uses it in production. |
|
@morozov I agree. In my company, we have a RW endpoint and an RO endpoint, we just created 2 connections, and don't use this class, and it works just fine. These features could be brought back at some point with a brand new design, that would have to avoid this unholy mix of composition and inheritance. |
This is how I see it should be implemented. The existing implementation has too many questionable assumptions to be the one and the only that is shipped with DBAL. |
0f368ee to
e6a7703
Compare
|
Ah I need to add an upgrade note for this. |
e6a7703 to
552eb88
Compare
UPGRADE.md
Outdated
| ## Deprecated `MasterSlaveConnection` | ||
|
|
||
| The naming is offensive, the implementation very questionable. Use regular | ||
| connections and switch between them explicitely. |
There was a problem hiding this comment.
Should it be “explicitly”? I'd also avoid “switch” — it implies shared state. Let's use “Use each endpoint connection explicitly”.
552eb88 to
0d621ba
Compare
Not only is the terminology needlessly hurtful, the design is a very leaky abstraction, and users are better off using regular connections and managing them themselves explicitly.
0d621ba to
5149e52
Compare
|
Closing in favor of #4054 |
Summary
MasterSlaveConnectionis left untouched, deprecated, copy/pasted/improvedAlternative to #4054
Targeting 2.11.x because of the deprecation.