Skip to content

Commit 758082a

Browse files
committed
bug #61091 [Lock] [MongoDB] Enforce readPreference=primary and writeConcern=majority (notrix)
This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [Lock] [MongoDB] Enforce readPreference=primary and writeConcern=majority | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #58397 | License | MIT ### The Problem A scenario was identified, similar to issue #58397, where a lock cannot be successfully released. This occurs when the application: 1. Provides a MongoDB Collection to the `MongoDbStore` with `readPreference` set to `primary`. 2. Has a default `readPreference` of `nearest` configured on the MongoDB manager. When `release()` is called on a lock, the component first issues a `DELETE` command to the primary MongoDB node. Immediately after, it sends a query to verify the deletion. However, this verification query incorrectly uses the `nearest` read preference from the Doctrine connection, often hitting a secondary node. If replication to the secondary has not yet completed, the verification fails, and an exception is thrown, incorrectly reporting that the lock release failed. ### The Solution This update enforces `readPreference`=`primary` for and `writeConcern`=`majority`. This ensures that read and write operations related to the lock are consistently routed, preventing the race condition and ensuring reliable lock releases. Commits ------- f0c00db [Lock] [MongoDB] Enforce readPreference=primary and writeConcern=majority
2 parents 3edb596 + f0c00db commit 758082a

File tree

1 file changed

+22
-8
lines changed

1 file changed

+22
-8
lines changed

src/Symfony/Component/Lock/Store/MongoDbStore.php

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use MongoDB\Driver\Exception\BulkWriteException;
2121
use MongoDB\Driver\Manager;
2222
use MongoDB\Driver\Query;
23+
use MongoDB\Driver\ReadPreference;
24+
use MongoDB\Driver\WriteConcern;
2325
use MongoDB\Exception\DriverRuntimeException;
2426
use MongoDB\Exception\InvalidArgumentException as MongoInvalidArgumentException;
2527
use MongoDB\Exception\UnsupportedException;
@@ -61,9 +63,9 @@ class MongoDbStore implements PersistingStoreInterface
6163
private float $initialTtl;
6264

6365
/**
64-
* @param Collection|Client|Manager|string $mongo An instance of a Collection or Client or URI @see https://docs.mongodb.com/manual/reference/connection-string/
65-
* @param array $options See below
66-
* @param float $initialTtl The expiration delay of locks in seconds
66+
* @param Collection|Database|Client|Manager|string $mongo An instance of a Collection or Client or URI @see https://docs.mongodb.com/manual/reference/connection-string/
67+
* @param array $options See below
68+
* @param float $initialTtl The expiration delay of locks in seconds
6769
*
6870
* @throws InvalidArgumentException If required options are not provided
6971
* @throws InvalidTtlException When the initial ttl is not valid
@@ -89,8 +91,10 @@ class MongoDbStore implements PersistingStoreInterface
8991
* to 0.0 and optionally leverage
9092
* self::createTtlIndex(int $expireAfterSeconds = 0).
9193
*
92-
* writeConcern and readConcern are not specified by MongoDbStore meaning the connection's settings will take effect.
93-
* readPreference is primary for all queries.
94+
* readConcern is not specified by MongoDbStore meaning the connection's settings will take effect.
95+
* writeConcern is majority for all update queries.
96+
* readPreference is primary for all read queries.
97+
*
9498
* @see https://docs.mongodb.com/manual/applications/replication/
9599
*/
96100
public function __construct(Collection|Database|Client|Manager|string $mongo, array $options = [], float $initialTtl = 300.0)
@@ -286,7 +290,11 @@ public function delete(Key $key)
286290
['limit' => 1]
287291
);
288292

289-
$this->getManager()->executeBulkWrite($this->namespace, $write);
293+
$this->getManager()->executeBulkWrite(
294+
$this->namespace,
295+
$write,
296+
['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]
297+
);
290298
}
291299

292300
public function exists(Key $key): bool
@@ -303,7 +311,9 @@ public function exists(Key $key): bool
303311
'limit' => 1,
304312
'projection' => ['_id' => 1],
305313
]
306-
));
314+
), [
315+
'readPreference' => new ReadPreference(ReadPreference::PRIMARY)
316+
]);
307317

308318
return [] !== $cursor->toArray();
309319
}
@@ -345,7 +355,11 @@ private function upsert(Key $key, float $ttl): void
345355
]
346356
);
347357

348-
$this->getManager()->executeBulkWrite($this->namespace, $write);
358+
$this->getManager()->executeBulkWrite(
359+
$this->namespace,
360+
$write,
361+
['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]
362+
);
349363
}
350364

351365
private function isDuplicateKeyException(BulkWriteException $e): bool

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy