From 21593f1d87168f9226298d50088ce8bbc8552c1f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 10:45:40 +0100 Subject: [PATCH 1/7] Fix inconsistency in naming --- components/lock.rst | 4 ++-- lock.rst | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 2b430f75de5..53bffff749e 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -42,10 +42,10 @@ resource. Then, a call to the :method:`Symfony\\Component\\Lock\\LockInterface:: method will try to acquire the lock:: // ... - $lock = $factory->createLock('pdf-invoice-generation'); + $lock = $factory->createLock('pdf-creation'); if ($lock->acquire()) { - // The resource "pdf-invoice-generation" is locked. + // The resource "pdf-creation" is locked. // You can compute and generate the invoice safely here. $lock->release(); diff --git a/lock.rst b/lock.rst index a821cf8edd1..c7903b7fd76 100644 --- a/lock.rst +++ b/lock.rst @@ -12,7 +12,7 @@ time to prevent race conditions from happening. The following example shows a typical usage of the lock:: - $lock = $lockFactory->createLock('pdf-invoice-generation'); + $lock = $lockFactory->createLock('pdf-creation'); if (!$lock->acquire()) { return; } @@ -59,7 +59,7 @@ this behavior by using the ``lock`` key like: lock: 'sqlite:///%kernel.project_dir%/var/lock.db' lock: 'mysql:host=127.0.0.1;dbname=app' lock: 'pgsql:host=127.0.0.1;dbname=app' - lock: 'pgsql+advisory:host=127.0.0.1;dbname=lock' + lock: 'pgsql+advisory:host=127.0.0.1;dbname=app' lock: 'sqlsrv:server=127.0.0.1;Database=app' lock: 'oci:host=127.0.0.1;dbname=app' lock: 'mongodb://127.0.0.1/app?collection=lock' @@ -111,7 +111,7 @@ this behavior by using the ``lock`` key like: pgsql:host=127.0.0.1;dbname=app - pgsql+advisory:host=127.0.0.1;dbname=lock + pgsql+advisory:host=127.0.0.1;dbname=app sqlsrv:server=127.0.0.1;Database=app @@ -149,7 +149,7 @@ this behavior by using the ``lock`` key like: ->resource('default', ['sqlite:///%kernel.project_dir%/var/lock.db']) ->resource('default', ['mysql:host=127.0.0.1;dbname=app']) ->resource('default', ['pgsql:host=127.0.0.1;dbname=app']) - ->resource('default', ['pgsql+advisory:host=127.0.0.1;dbname=lock']) + ->resource('default', ['pgsql+advisory:host=127.0.0.1;dbname=app']) ->resource('default', ['sqlsrv:server=127.0.0.1;Database=app']) ->resource('default', ['oci:host=127.0.0.1;dbname=app']) ->resource('default', ['mongodb://127.0.0.1/app?collection=lock']) From d50aeb6a8b04fce98ccbe3e28eac22535622441d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 10:48:57 +0100 Subject: [PATCH 2/7] Fix lock example --- lock.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lock.rst b/lock.rst index c7903b7fd76..f370c43c9dc 100644 --- a/lock.rst +++ b/lock.rst @@ -207,8 +207,8 @@ Locking a Dynamic Resource Sometimes the application is able to cut the resource into small pieces in order to lock a small subset of processes and let others through. The previous example -showed how to lock the ``$pdf->getOrCreatePdf('terms-of-use')`` for everybody, -now let's see how to lock ``$pdf->getOrCreatePdf($version)`` only for +showed how to lock the ``$pdf->getOrCreatePdf()`` call for everybody, +now let's see how to lock a ``$pdf->getOrCreatePdf($version)`` call only for processes asking for the same ``$version``:: // src/Controller/PdfController.php @@ -222,7 +222,7 @@ processes asking for the same ``$version``:: #[Route('/download/{version}/terms-of-use.pdf')] public function downloadPdf($version, LockFactory $lockFactory, MyPdfGeneratorService $pdf) { - $lock = $lockFactory->createLock($version); + $lock = $lockFactory->createLock('pdf-creation-'.$version); $lock->acquire(true); // heavy computation From 48955a9ecdc21c9190c7371d43530257599cd0e6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 10:52:24 +0100 Subject: [PATCH 3/7] Add a lock example and removed references to service ids --- lock.rst | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lock.rst b/lock.rst index f370c43c9dc..37ddcf7b2c7 100644 --- a/lock.rst +++ b/lock.rst @@ -170,7 +170,7 @@ Locking a Resource ------------------ To lock the default resource, autowire the lock factory using -:class:`Symfony\\Component\\Lock\\LockFactory` (service id ``lock.factory``):: +:class:`Symfony\\Component\\Lock\\LockFactory`:: // src/Controller/PdfController.php namespace App\Controller; @@ -284,10 +284,24 @@ provides :ref:`named lock `: ; }; +An autowiring alias is created for each named lock with a name using the camel +case version of its name suffixed by ``LockFactory``. -Each name becomes a service where the service id is part of the name of the -lock (e.g. ``lock.invoice.factory``). An autowiring alias is also created for -each lock using the camel case version of its name suffixed by ``LockFactory`` -- e.g. ``invoice`` can be injected automatically by naming the argument +For instance, the ``invoice`` lock can be injected by naming the argument ``$invoiceLockFactory`` and type-hinting it with -:class:`Symfony\\Component\\Lock\\LockFactory`. +:class:`Symfony\\Component\\Lock\\LockFactory`: + + // src/Controller/PdfController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Lock\LockFactory; + + class PdfController extends AbstractController + { + #[Route('/download/terms-of-use.pdf')] + public function downloadPdf(LockFactory $invoiceLockFactory, MyPdfGeneratorService $pdf) + { + // ... + } + } From 4288a73a830dba12292c953d18809bd980e8e8ba Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 10:55:06 +0100 Subject: [PATCH 4/7] Fix inconsistent titles --- lock.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lock.rst b/lock.rst index 37ddcf7b2c7..fa7330e8c19 100644 --- a/lock.rst +++ b/lock.rst @@ -22,8 +22,8 @@ The following example shows a typical usage of the lock:: $lock->release(); -Installation ------------- +Installing +---------- In applications using :ref:`Symfony Flex `, run this command to install the Lock component: @@ -32,8 +32,8 @@ install the Lock component: $ composer require symfony/lock -Configuring Lock with FrameworkBundle -------------------------------------- +Configuring +----------- By default, Symfony provides a :ref:`Semaphore ` when available, or a :ref:`Flock ` otherwise. You can configure @@ -236,8 +236,8 @@ processes asking for the same ``$version``:: .. _lock-named-locks: -Named Lock ----------- +Naming Locks +------------ If the application needs different kind of Stores alongside each other, Symfony provides :ref:`named lock `: From 6fe26eaa62b32541feabb5e61039df3515a3fd2b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 11:41:33 +0100 Subject: [PATCH 5/7] Make various changes to the lock docs --- components/lock.rst | 146 +++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 69 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 53bffff749e..c79c8bc85b3 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -81,20 +81,21 @@ continue the job in another process using the same lock:: use Symfony\Component\Lock\Lock; $key = new Key('article.'.$article->getId()); - $lock = new Lock($key, $this->store, 300, false); + $lock = new Lock($key, $this->store, autoRelease: false); $lock->acquire(true); $this->bus->dispatch(new RefreshTaxonomy($article, $key)); .. note:: - Don't forget to disable the autoRelease to avoid releasing the lock when - the destructor is called. + Don't forget to disable the ``autoRelease`` flag in the ``Lock`` + constructor to avoid releasing the lock when the destructor is called. -Not all stores are compatible with serialization and cross-process locking: -for example, the kernel will automatically release semaphores acquired by the +Not all stores are compatible with serialization and cross-process locking: for +example, the kernel will automatically release semaphores acquired by the :ref:`SemaphoreStore ` store. If you use an incompatible -store, an exception will be thrown when the application tries to serialize the key. +store (see :ref:`lock stores <_lock-stores>` for supported stores), an +exception will be thrown when the application tries to serialize the key. .. _lock-blocking-locks: @@ -102,12 +103,10 @@ Blocking Locks -------------- By default, when a lock cannot be acquired, the ``acquire`` method returns -``false`` immediately. To wait (indefinitely) until the lock -can be created, pass ``true`` as the argument of the ``acquire()`` method. This -is called a **blocking lock** because the execution of your application stops -until the lock is acquired. - -Some of the built-in ``Store`` classes support this feature:: +``false`` immediately. To wait (indefinitely) until the lock can be created, +pass ``true`` as the argument of the ``acquire()`` method. This is called a +**blocking lock** because the execution of your application stops until the +lock is acquired:: use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\Store\RedisStore; @@ -115,23 +114,23 @@ Some of the built-in ``Store`` classes support this feature:: $store = new RedisStore(new \Predis\Client('tcp://localhost:6379')); $factory = new LockFactory($store); - $lock = $factory->createLock('notification-flush'); + $lock = $factory->createLock('pdf-creation'); $lock->acquire(true); -When the provided store does not implement the -:class:`Symfony\\Component\\Lock\\BlockingStoreInterface` interface, the -``Lock`` class will retry to acquire the lock in a non-blocking way until the -lock is acquired. However, the ``Lock`` class also provides the default logic to -acquire locks in blocking mode when the store does not implement the -``BlockingStoreInterface`` interface. +When the store does not support blocking locks by implementing the +:class:`Symfony\\Component\\Lock\\BlockingStoreInterface` interface (see +:ref:`lock stores <_lock-stores>` for supported stores), the ``Lock`` class +will retry to acquire the lock in a non-blocking way until the lock is +acquired. Expiring Locks -------------- Locks created remotely are difficult to manage because there is no way for the remote ``Store`` to know if the locker process is still alive. Due to bugs, -fatal errors or segmentation faults, it cannot be guaranteed that ``release()`` -method will be called, which would cause the resource to be locked infinitely. +fatal errors or segmentation faults, it cannot be guaranteed that the +``release()`` method will be called, which would cause the resource to be +locked infinitely. The best solution in those cases is to create **expiring locks**, which are released automatically after some amount of time has passed (called TTL for @@ -146,7 +145,7 @@ method, the resource will stay locked until the timeout:: // ... // create an expiring lock that lasts 30 seconds (default is 300.0) - $lock = $factory->createLock('charts-generation', 30); + $lock = $factory->createLock('pdf-creation', ttl: 30); if (!$lock->acquire()) { return; @@ -167,7 +166,7 @@ then use the :method:`Symfony\\Component\\Lock\\LockInterface::refresh` method to reset the TTL to its original value:: // ... - $lock = $factory->createLock('charts-generation', 30); + $lock = $factory->createLock('pdf-creation', ttl: 30); if (!$lock->acquire()) { return; @@ -188,7 +187,7 @@ to reset the TTL to its original value:: Another useful technique for long-running tasks is to pass a custom TTL as an argument of the ``refresh()`` method to change the default lock TTL:: - $lock = $factory->createLock('charts-generation', 30); + $lock = $factory->createLock('pdf-creation', ttl: 30); // ... // refresh the lock for 30 seconds $lock->refresh(); @@ -204,12 +203,12 @@ Automatically Releasing The Lock ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Locks are automatically released when their Lock objects are destroyed. This is -an implementation detail that will be important when sharing Locks between +an implementation detail that is important when sharing Locks between processes. In the example below, ``pcntl_fork()`` creates two processes and the Lock will be released automatically as soon as one process finishes:: // ... - $lock = $factory->createLock('report-generation', 3600); + $lock = $factory->createLock('pdf-creation', 3600); if (!$lock->acquire()) { return; } @@ -228,26 +227,28 @@ Lock will be released automatically as soon as one process finishes:: } // ... -To disable this behavior, set to ``false`` the third argument of -``LockFactory::createLock()``. That will make the lock acquired for 3600 seconds -or until ``Lock::release()`` is called. +To disable this behavior, set the ``autoRelease`` argument of +``LockFactory::createLock()`` to ``false``. That will make the lock acquired +for 3600 seconds or until ``Lock::release()`` is called:: + + $lock = $factory->createLock('pdf-creation', 3600, autoRelease: false); Shared Locks ------------ -A shared or `readers–writer lock`_ is a synchronization primitive that allows +A shared or `readers-writer lock`_ is a synchronization primitive that allows concurrent access for read-only operations, while write operations require exclusive access. This means that multiple threads can read the data in parallel but an exclusive lock is needed for writing or modifying data. They are used for example for data structures that cannot be updated atomically and are invalid until the update is complete. -Use the :method:`Symfony\\Component\\Lock\\SharedLockInterface::acquireRead` method -to acquire a read-only lock, and the existing +Use the :method:`Symfony\\Component\\Lock\\SharedLockInterface::acquireRead` +method to acquire a read-only lock, and :method:`Symfony\\Component\\Lock\\LockInterface::acquire` method to acquire a write lock:: - $lock = $factory->createLock('user'.$user->id); + $lock = $factory->createLock('user-'.$user->id); if (!$lock->acquireRead()) { return; } @@ -255,7 +256,7 @@ write lock:: Similar to the ``acquire()`` method, pass ``true`` as the argument of ``acquireRead()`` to acquire the lock in a blocking mode:: - $lock = $factory->createLock('user'.$user->id); + $lock = $factory->createLock('user-'.$user->id); $lock->acquireRead(true); .. note:: @@ -263,26 +264,27 @@ to acquire the lock in a blocking mode:: The `priority policy`_ of Symfony's shared locks depends on the underlying store (e.g. Redis store prioritizes readers vs writers). -When a read-only lock is acquired with the method ``acquireRead()``, it's +When a read-only lock is acquired with the ``acquireRead()`` method, it's possible to **promote** the lock, and change it to write lock, by calling the ``acquire()`` method:: - $lock = $factory->createLock('user'.$userId); + $lock = $factory->createLock('user-'.$userId); $lock->acquireRead(true); if (!$this->shouldUpdate($userId)) { return; } - $lock->acquire(true); // Promote the lock to write lock + $lock->acquire(true); // Promote the lock to a write lock $this->update($userId); In the same way, it's possible to **demote** a write lock, and change it to a read-only lock by calling the ``acquireRead()`` method. When the provided store does not implement the -:class:`Symfony\\Component\\Lock\\SharedLockStoreInterface` interface, the -``Lock`` class will fallback to a write lock by calling the ``acquire()`` method. +:class:`Symfony\\Component\\Lock\\SharedLockStoreInterface` interface (see +:ref:`lock stores <_lock-stores>` for supported stores), the ``Lock`` class +will fallback to a write lock by calling the ``acquire()`` method. The Owner of The Lock --------------------- @@ -295,8 +297,8 @@ a lock, you can use the ``isAcquired()`` method:: // We (still) own the lock } -Because of the fact that some lock stores have expiring locks (as seen and explained -above), it is possible for an instance to lose the lock it acquired automatically:: +Because some lock stores have expiring locks, it is possible for an instance to +lose the lock it acquired automatically:: // If we cannot acquire ourselves, it means some other process is already working on it if (!$lock->acquire()) { @@ -322,13 +324,15 @@ above), it is possible for an instance to lose the lock it acquired automaticall A common pitfall might be to use the ``isAcquired()`` method to check if a lock has already been acquired by any process. As you can see in this example you have to use ``acquire()`` for this. The ``isAcquired()`` method is used to check - if the lock has been acquired by the **current process** only! + if the lock has been acquired by the **current process** only. .. [1] Technically, the true owners of the lock are the ones that share the same instance of ``Key``, not ``Lock``. But from a user perspective, ``Key`` is internal and you will likely only be working with the ``Lock`` instance so it's easier to think of the ``Lock`` instance as being the one that is the owner of the lock. +.. _lock-stores: + Available Stores ---------------- @@ -378,7 +382,7 @@ when the PHP process ends):: Beware that some file systems (such as some types of NFS) do not support locking. In those cases, it's better to use a directory on a local disk - drive or a remote store based on PDO, Redis or Memcached. + drive or a remote store. .. _lock-store-memcached: @@ -431,7 +435,7 @@ Option Description gcProbablity Should a TTL Index be created expressed as a probability from 0.0 to 1.0 (Defaults to ``0.001``) database The name of the database collection The name of the collection -uriOptions Array of uri options for `MongoDBClient::__construct`_ +uriOptions Array of URI options for `MongoDBClient::__construct`_ driverOptions Array of driver options for `MongoDBClient::__construct`_ ============= ================================================================================================ @@ -521,7 +525,7 @@ locks:: use Symfony\Component\Lock\Store\PostgreSqlStore; // a PDO instance or DSN for lazy connecting through PDO - $databaseConnectionOrDSN = 'pgsql:host=localhost;port=5634;dbname=lock'; + $databaseConnectionOrDSN = 'pgsql:host=localhost;port=5634;dbname=app'; $store = new PostgreSqlStore($databaseConnectionOrDSN, ['db_username' => 'myuser', 'db_password' => 'mypassword']); In opposite to the ``PdoStore``, the ``PostgreSqlStore`` does not need a table to @@ -579,10 +583,10 @@ CombinedStore ~~~~~~~~~~~~~ The CombinedStore is designed for High Availability applications because it -manages several stores in sync (for example, several Redis servers). When a lock -is being acquired, it forwards the call to all the managed stores, and it -collects their responses. If a simple majority of stores have acquired the lock, -then the lock is considered as acquired; otherwise as not acquired:: +manages several stores in sync (for example, several Redis servers). When a +lock is acquired, it forwards the call to all the managed stores, and it +collects their responses. If a simple majority of stores have acquired the +lock, then the lock is considered acquired:: use Symfony\Component\Lock\Store\CombinedStore; use Symfony\Component\Lock\Store\RedisStore; @@ -600,14 +604,19 @@ then the lock is considered as acquired; otherwise as not acquired:: Instead of the simple majority strategy (``ConsensusStrategy``) an ``UnanimousStrategy`` can be used to require the lock to be acquired in all -the stores. +the stores:: + + use Symfony\Component\Lock\Store\CombinedStore; + use Symfony\Component\Lock\Strategy\UnanimousStrategy; + + $store = new CombinedStore($stores, new UnanimousStrategy()); .. caution:: In order to get high availability when using the ``ConsensusStrategy``, the minimum cluster size must be three servers. This allows the cluster to keep working when a single server fails (because this strategy requires that the - lock is acquired in more than half of the servers). + lock is acquired for more than half of the servers). .. _lock-store-zookeeper: @@ -651,7 +660,7 @@ the true owner of the lock. This token is stored in the :class:`Symfony\\Component\\Lock\\Key` object and is used internally by the ``Lock``. -Every concurrent process must store the ``Lock`` in the same server. Otherwise two +Every concurrent process must store the ``Lock`` on the same server. Otherwise two different machines may allow two different processes to acquire the same ``Lock``. .. caution:: @@ -675,10 +684,10 @@ The ``Lock`` provides several methods to check its health. The ``isExpired()`` method checks whether or not its lifetime is over and the ``getRemainingLifetime()`` method returns its time to live in seconds. -Using the above methods, a more robust code would be:: +Using the above methods, a robust code would be:: // ... - $lock = $factory->createLock('invoice-publication', 30); + $lock = $factory->createLock('pdf-creation', 30); if (!$lock->acquire()) { return; @@ -707,7 +716,7 @@ Using the above methods, a more robust code would be:: may increase that time a lot (up to a few seconds). Take that into account when choosing the right TTL. -By design, locks are stored in servers with a defined lifetime. If the date or +By design, locks are stored on servers with a defined lifetime. If the date or time of the machine changes, a lock could be released sooner than expected. .. caution:: @@ -737,15 +746,14 @@ Some file systems (such as some types of NFS) do not support locking. All concurrent processes must use the same physical file system by running on the same machine and using the same absolute path to the lock directory. - By definition, usage of ``FlockStore`` in an HTTP context is incompatible - with multiple front servers, unless to ensure that the same resource will - always be locked on the same machine or to use a well configured shared file - system. + Using a ``FlockStore`` in an HTTP context is incompatible with multiple + front servers, unless to ensure that the same resource will always be + locked on the same machine or to use a well configured shared file system. -Files on the file system can be removed during a maintenance operation. For instance, -to clean up the ``/tmp`` directory or after a reboot of the machine when a directory -uses tmpfs. It's not an issue if the lock is released when the process ended, but -it is in case of ``Lock`` reused between requests. +Files on the file system can be removed during a maintenance operation. For +instance, to clean up the ``/tmp`` directory or after a reboot of the machine +when a directory uses ``tmpfs``. It's not an issue if the lock is released when +the process ended, but it is in case of ``Lock`` reused between requests. .. caution:: @@ -791,8 +799,8 @@ MongoDbStore .. caution:: The locked resource name is indexed in the ``_id`` field of the lock - collection. Beware that in MongoDB an indexed field's value can be - `a maximum of 1024 bytes in length`_ inclusive of structural overhead. + collection. Beware that an indexed field's value in MongoDB can be + `a maximum of 1024 bytes in length`_ including the structural overhead. A TTL index must be used to automatically clean up expired locks. Such an index can be created manually: @@ -810,8 +818,8 @@ about `Expire Data from Collections by Setting TTL`_ in MongoDB. .. tip:: - ``MongoDbStore`` will attempt to automatically create a TTL index. - It's recommended to set constructor option ``gcProbablity = 0.0`` to + ``MongoDbStore`` will attempt to automatically create a TTL index. It's + recommended to set constructor option ``gcProbablity`` to ``0.0`` to disable this behavior if you have manually dealt with TTL index creation. .. caution:: @@ -827,7 +835,7 @@ the collection's settings will take effect. Read more about `Replica Set Read and Write Semantics`_ in MongoDB. PdoStore -~~~~~~~~~~ +~~~~~~~~ The PdoStore relies on the `ACID`_ properties of the SQL engine. @@ -981,5 +989,5 @@ are still running. .. _`PHP semaphore functions`: https://www.php.net/manual/en/book.sem.php .. _`Replica Set Read and Write Semantics`: https://docs.mongodb.com/manual/applications/replication/ .. _`ZooKeeper`: https://zookeeper.apache.org/ -.. _`readers–writer lock`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock +.. _`readers-writer lock`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock .. _`priority policy`: https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Priority_policies From 80e57635ca74ba95ecd59359c854cae1ddb43370 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2022 12:06:43 +0100 Subject: [PATCH 6/7] Fix bad ref --- components/lock.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index c79c8bc85b3..218bfa2bba6 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -94,7 +94,7 @@ continue the job in another process using the same lock:: Not all stores are compatible with serialization and cross-process locking: for example, the kernel will automatically release semaphores acquired by the :ref:`SemaphoreStore ` store. If you use an incompatible -store (see :ref:`lock stores <_lock-stores>` for supported stores), an +store (see :ref:`lock stores ` for supported stores), an exception will be thrown when the application tries to serialize the key. .. _lock-blocking-locks: @@ -119,7 +119,7 @@ lock is acquired:: When the store does not support blocking locks by implementing the :class:`Symfony\\Component\\Lock\\BlockingStoreInterface` interface (see -:ref:`lock stores <_lock-stores>` for supported stores), the ``Lock`` class +:ref:`lock stores ` for supported stores), the ``Lock`` class will retry to acquire the lock in a non-blocking way until the lock is acquired. @@ -283,7 +283,7 @@ read-only lock by calling the ``acquireRead()`` method. When the provided store does not implement the :class:`Symfony\\Component\\Lock\\SharedLockStoreInterface` interface (see -:ref:`lock stores <_lock-stores>` for supported stores), the ``Lock`` class +:ref:`lock stores ` for supported stores), the ``Lock`` class will fallback to a write lock by calling the ``acquire()`` method. The Owner of The Lock From ef38c4ef50f651e68519a1e0ea802a76b60084a7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Nov 2022 08:08:54 +0100 Subject: [PATCH 7/7] Tweak wording --- components/lock.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 218bfa2bba6..1bc71a38d6b 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -88,8 +88,9 @@ continue the job in another process using the same lock:: .. note:: - Don't forget to disable the ``autoRelease`` flag in the ``Lock`` - constructor to avoid releasing the lock when the destructor is called. + Don't forget to set the ``autoRelease`` argument to ``false`` in the + ``Lock`` constructor to avoid releasing the lock when the destructor is + called. Not all stores are compatible with serialization and cross-process locking: for example, the kernel will automatically release semaphores acquired by the @@ -208,7 +209,7 @@ processes. In the example below, ``pcntl_fork()`` creates two processes and the Lock will be released automatically as soon as one process finishes:: // ... - $lock = $factory->createLock('pdf-creation', 3600); + $lock = $factory->createLock('pdf-creation'); if (!$lock->acquire()) { return; } @@ -231,7 +232,7 @@ To disable this behavior, set the ``autoRelease`` argument of ``LockFactory::createLock()`` to ``false``. That will make the lock acquired for 3600 seconds or until ``Lock::release()`` is called:: - $lock = $factory->createLock('pdf-creation', 3600, autoRelease: false); + $lock = $factory->createLock('pdf-creation', ttl: 3600, autoRelease: false); Shared Locks ------------ @@ -265,7 +266,7 @@ to acquire the lock in a blocking mode:: store (e.g. Redis store prioritizes readers vs writers). When a read-only lock is acquired with the ``acquireRead()`` method, it's -possible to **promote** the lock, and change it to write lock, by calling the +possible to **promote** the lock, and change it to a write lock, by calling the ``acquire()`` method:: $lock = $factory->createLock('user-'.$userId);