Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1d8680f

Browse filesBrowse files
committed
Add a documentation page for lock in FW
1 parent 3ef6848 commit 1d8680f
Copy full SHA for 1d8680f

File tree

Expand file treeCollapse file tree

3 files changed

+301
-54
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+301
-54
lines changed

‎components/lock.rst

Copy file name to clipboardExpand all lines: components/lock.rst
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ The Lock Component
88
The Lock Component creates and manages `locks`_, a mechanism to provide
99
exclusive access to a shared resource.
1010

11+
If you're using the Symfony Framework, read the
12+
:doc:`Symfony Framework Lock documentation </lock>`.
13+
1114
Installation
1215
------------
1316

‎lock.rst

Copy file name to clipboard
+291Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
.. index::
2+
single: Lock
3+
4+
Dealing with concurrency with Lock
5+
==================================
6+
7+
When a program runs concurrently, some part of code which modify shared
8+
resources should not be accessed by multiple processes at the same time.
9+
Symfony's :doc:`Lock </components/lock>` provides a locking mechanism to ensure
10+
that only one process is running the critical section of code at any point of
11+
time to prevent race condition from happening.
12+
13+
The following example shows a typical usage of the lock::
14+
15+
$lock = $lockFactory->createLock('pdf-invoice-generation');
16+
if (!$lock->acquire()) {
17+
return;
18+
}
19+
20+
// critical section of code
21+
$service->method();
22+
23+
$lock->release();
24+
25+
Installation
26+
------------
27+
28+
In applications using :ref:`Symfony Flex <symfony-flex>`, run this command to
29+
install messenger:
30+
31+
.. code-block:: terminal
32+
33+
$ composer require symfony/lock
34+
35+
Configuring Lock with FrameworkBundle
36+
-------------------------------------
37+
38+
By default, Symfony provides a :doc:`Semaphore<lock-store-semaphore>`
39+
when available, or a :doc:`Flock<lock-store-flock>` otherwise. You can configure
40+
this behavior by using the ``lock`` key like:
41+
42+
.. configuration-block::
43+
44+
.. code-block:: yaml
45+
46+
# config/packages/lock.yaml
47+
framework:
48+
lock: ~
49+
lock: 'flock'
50+
lock: 'flock:///path/to/file'
51+
lock: 'semaphore'
52+
lock: 'memcached://m1.docker'
53+
lock: ['memcached://m1.docker', 'memcached://m2.docker']
54+
lock: 'redis://r1.docker'
55+
lock: ['redis://r1.docker', 'redis://r2.docker']
56+
lock: 'zookeeper://z1.docker'
57+
lock: 'zookeeper://z1.docker,z2.docker'
58+
lock: 'sqlite:///%kernel.project_dir%/var/lock.db'
59+
lock: 'mysql:host=127.0.0.1;dbname=lock'
60+
lock: 'pgsql:host=127.0.0.1;dbname=lock'
61+
lock: 'sqlsrv:server=localhost;Database=test'
62+
lock: 'oci:host=localhost;dbname=test'
63+
lock: '%env(LOCK_DSN)%'
64+
65+
# named locks
66+
lock:
67+
invoice: ['semaphore', 'redis://r2.docker']
68+
report: 'semaphore'
69+
70+
.. code-block:: xml
71+
72+
<!-- config/packages/lock.xml -->
73+
<?xml version="1.0" encoding="UTF-8" ?>
74+
<container xmlns="http://symfony.com/schema/dic/services"
75+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
76+
xmlns:framework="http://symfony.com/schema/dic/symfony"
77+
xsi:schemaLocation="http://symfony.com/schema/dic/services
78+
https://symfony.com/schema/dic/services/services-1.0.xsd
79+
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
80+
81+
<framework:config>
82+
<framework:lock>
83+
<framework:resource>flock</framework:resource>
84+
85+
<framework:resource>flock:///path/to/file</framework:resource>
86+
87+
<framework:resource>semaphore</framework:resource>
88+
89+
<framework:resource>memcached://m1.docker</framework:resource>
90+
91+
<framework:resource>memcached://m1.docker</framework:resource>
92+
<framework:resource>memcached://m2.docker</framework:resource>
93+
94+
<framework:resource>redis://r1.docker</framework:resource>
95+
96+
<framework:resource>redis://r1.docker</framework:resource>
97+
<framework:resource>redis://r2.docker</framework:resource>
98+
99+
<framework:resource>zookeeper://z1.docker</framework:resource>
100+
101+
<framework:resource>zookeeper://z1.docker,z2.docker</framework:resource>
102+
103+
<framework:resource>sqlite:///%kernel.project_dir%/var/lock.db</framework:resource>
104+
105+
<framework:resource>mysql:host=127.0.0.1;dbname=lock</framework:resource>
106+
107+
<framework:resource>pgsql:host=127.0.0.1;dbname=lock</framework:resource>
108+
109+
<framework:resource>sqlsrv:server=localhost;Database=test</framework:resource>
110+
111+
<framework:resource>oci:host=localhost;dbname=test</framework:resource>
112+
113+
<framework:resource>%env(LOCK_DSN)%</framework:resource>
114+
115+
<!-- named locks -->
116+
<framework:resource name="invoice">semaphore</framework:resource>
117+
<framework:resource name="invoice">redis://r2.docker</framework:resource>
118+
<framework:resource name="report">semaphore</framework:resource>
119+
</framework:lock>
120+
</framework:config>
121+
</container>
122+
123+
.. code-block:: php
124+
125+
// config/packages/lock.php
126+
$container->loadFromExtension('framework', [
127+
'lock' => null,
128+
'lock' => 'flock',
129+
'lock' => 'flock:///path/to/file',
130+
'lock' => 'semaphore',
131+
'lock' => 'memcached://m1.docker',
132+
'lock' => ['memcached://m1.docker', 'memcached://m2.docker'],
133+
'lock' => 'redis://r1.docker',
134+
'lock' => ['redis://r1.docker', 'redis://r2.docker'],
135+
'lock' => 'zookeeper://z1.docker',
136+
'lock' => 'zookeeper://z1.docker,z2.docker',
137+
'lock' => 'sqlite:///%kernel.project_dir%/var/lock.db',
138+
'lock' => 'mysql:host=127.0.0.1;dbname=lock',
139+
'lock' => 'pgsql:host=127.0.0.1;dbname=lock',
140+
'lock' => 'sqlsrv:server=localhost;Database=test',
141+
'lock' => 'oci:host=localhost;dbname=test',
142+
'lock' => '%env(LOCK_DSN)%',
143+
144+
// named locks
145+
'lock' => [
146+
'invoice' => ['semaphore', 'redis://r2.docker'],
147+
'report' => 'semaphore',
148+
],
149+
]);
150+
151+
Locking a Resource
152+
------------------
153+
154+
To lock the default resource, autowire the lock using
155+
:class:`Symfony\\Component\\Lock\\LockInterface` (service id ``lock``)::
156+
157+
// src/Controller/PdfController.php
158+
namespace App\Controller;
159+
160+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
161+
use Symfony\Component\Lock\LockInterface;
162+
163+
class PdfController extends AbstractController
164+
{
165+
/**
166+
* @Route("/download/terms-of-use.pdf")
167+
*/
168+
public function downloadPdf(LockInterface $lock, MyPdfGeneratorService $pdf)
169+
{
170+
$lock->acquire(true);
171+
172+
// heavy computation
173+
$myPdf = $pdf->getOrCreatePdf();
174+
175+
$lock->release();
176+
177+
// ...
178+
}
179+
}
180+
181+
.. caution::
182+
183+
The same instance of ``LockInterface`` won't block when calling `acquire``
184+
multiple times. If several services share the same ``lock`` service, they
185+
won't lock each other, use ``LockFactory`` instead.
186+
187+
Locking a Dynamic Resource
188+
--------------------------
189+
190+
Sometimes the application is able to cut the resource into small pieces in order
191+
to lock a small subset of process and let other through. In our previous example
192+
with see how to lock the ``$pdf->getOrCreatePdf('terms-of-use')`` for everybody,
193+
now let's see how to lock ``$pdf->getOrCreatePdf($version)`` only for
194+
processes asking for the same ``$version``::
195+
196+
// src/Controller/PdfController.php
197+
namespace App\Controller;
198+
199+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
200+
use Symfony\Component\Lock\LockInterface;
201+
202+
class PdfController extends AbstractController
203+
{
204+
/**
205+
* @Route("/download/{version}/terms-of-use.pdf")
206+
*/
207+
public function downloadPdf($version, LockFactory $lockFactory, MyPdfGeneratorService $pdf)
208+
{
209+
$lock = $lockFactory->createLock($version);
210+
$lock->acquire(true);
211+
212+
// heavy computation
213+
$myPdf = $pdf->getOrCreatePdf($version);
214+
215+
$lock->release();
216+
217+
// ...
218+
}
219+
}
220+
221+
Named Lock
222+
----------
223+
224+
If the application needs different kind of Stores alongside each other, Symfony
225+
provides :doc:`named lock <reference-lock-resources-name>`::
226+
227+
.. configuration-block::
228+
229+
.. code-block:: yaml
230+
231+
# config/packages/lock.yaml
232+
framework:
233+
lock:
234+
invoice: ['semaphore', 'redis://r2.docker']
235+
report: 'semaphore'
236+
237+
.. code-block:: xml
238+
239+
<!-- config/packages/lock.xml -->
240+
<?xml version="1.0" encoding="UTF-8" ?>
241+
<container xmlns="http://symfony.com/schema/dic/services"
242+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
243+
xmlns:framework="http://symfony.com/schema/dic/symfony"
244+
xsi:schemaLocation="http://symfony.com/schema/dic/services
245+
https://symfony.com/schema/dic/services/services-1.0.xsd
246+
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
247+
248+
<framework:config>
249+
<framework:lock>
250+
<framework:resource name="invoice">semaphore</framework:resource>
251+
<framework:resource name="invoice">redis://r2.docker</framework:resource>
252+
<framework:resource name="report">semaphore</framework:resource>
253+
</framework:lock>
254+
</framework:config>
255+
</container>
256+
257+
.. code-block:: php
258+
259+
// config/packages/lock.php
260+
$container->loadFromExtension('framework', [
261+
'lock' => [
262+
'invoice' => ['semaphore', 'redis://r2.docker'],
263+
'report' => 'semaphore',
264+
],
265+
]);
266+
267+
Each name becomes a service where the service id suffixed by the name of the
268+
lock (e.g. ``lock.invoice``). An autowiring alias is also created for each lock
269+
using the camel case version of its name suffixed by ``Lock`` - e.g. ``invoice``
270+
can be injected automatically by naming the argument ``$invoiceLock`` and
271+
type-hinting it with :class:`Symfony\\Component\\Lock\\LockInterface`.
272+
273+
Symfony also provide a corresponding factory and store following the same rules
274+
(e.g. ``invoice`` generates a ``lock.invoice.factory`` and
275+
``lock.invoice.store``, both can be injected automatically by naming
276+
respectively ``$invoiceLockFactory`` and ``invoiceLockStore`` and type-hinted
277+
with :class:`Symfony\\Component\\Lock\\LockFactory` and
278+
:class:`Symfony\\Component\\Lock\\PersistingStoreInterface`)
279+
280+
Blocking Store
281+
--------------
282+
283+
If you want to use the ``RetryTillSaveStore`` for :ref:`non-blocking locks <lock-blocking-locks>`,
284+
you can do it by :doc:`decorating the store </service_container/service_decoration>` service:
285+
286+
.. code-block:: yaml
287+
288+
lock.default.retry_till_save.store:
289+
class: Symfony\Component\Lock\Store\RetryTillSaveStore
290+
decorates: lock.default.store
291+
arguments: ['@lock.default.retry.till.save.store.inner', 100, 50]

‎reference/configuration/framework.rst

Copy file name to clipboardExpand all lines: reference/configuration/framework.rst
+7-54Lines changed: 7 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2769,21 +2769,7 @@ A list of lock stores to be created by the framework extension.
27692769
27702770
# config/packages/lock.yaml
27712771
framework:
2772-
# these are all the supported lock stores
2773-
lock: ~
2774-
lock: 'flock'
2775-
lock: 'flock:///path/to/file'
2776-
lock: 'semaphore'
2777-
lock: 'memcached://m1.docker'
2778-
lock: ['memcached://m1.docker', 'memcached://m2.docker']
2779-
lock: 'redis://r1.docker'
2780-
lock: ['redis://r1.docker', 'redis://r2.docker']
2781-
lock: '%env(MEMCACHED_OR_REDIS_URL)%'
2782-
2783-
# named locks
2784-
lock:
2785-
invoice: ['redis://r1.docker', 'redis://r2.docker']
2786-
report: 'semaphore'
2772+
lock: '%env(LOCK_DSN)%'
27872773
27882774
.. code-block:: xml
27892775
@@ -2798,29 +2784,7 @@ A list of lock stores to be created by the framework extension.
27982784
27992785
<framework:config>
28002786
<framework:lock>
2801-
<!-- these are all the supported lock stores -->
2802-
<framework:resource>flock</framework:resource>
2803-
2804-
<framework:resource>flock:///path/to/file</framework:resource>
2805-
2806-
<framework:resource>semaphore</framework:resource>
2807-
2808-
<framework:resource>memcached://m1.docker</framework:resource>
2809-
2810-
<framework:resource>memcached://m1.docker</framework:resource>
2811-
<framework:resource>memcached://m2.docker</framework:resource>
2812-
2813-
<framework:resource>redis://r1.docker</framework:resource>
2814-
2815-
<framework:resource>redis://r1.docker</framework:resource>
2816-
<framework:resource>redis://r2.docker</framework:resource>
2817-
2818-
<framework:resource>%env(REDIS_URL)%</framework:resource>
2819-
2820-
<!-- named locks -->
2821-
<framework:resource name="invoice">redis://r1.docker</framework:resource>
2822-
<framework:resource name="invoice">redis://r2.docker</framework:resource>
2823-
<framework:resource name="report">semaphore</framework:resource>
2787+
<framework:resource>%env(LOCK_DSN)%</framework:resource>
28242788
</framework:lock>
28252789
</framework:config>
28262790
</container>
@@ -2829,24 +2793,13 @@ A list of lock stores to be created by the framework extension.
28292793
28302794
// config/packages/lock.php
28312795
$container->loadFromExtension('framework', [
2832-
// these are all the supported lock stores
2833-
'lock' => null,
2834-
'lock' => 'flock',
2835-
'lock' => 'flock:///path/to/file',
2836-
'lock' => 'semaphore',
2837-
'lock' => 'memcached://m1.docker',
2838-
'lock' => ['memcached://m1.docker', 'memcached://m2.docker'],
2839-
'lock' => 'redis://r1.docker',
2840-
'lock' => ['redis://r1.docker', 'redis://r2.docker'],
2841-
'lock' => '%env(MEMCACHED_OR_REDIS_URL)%',
2842-
2843-
// named locks
2844-
'lock' => [
2845-
'invoice' => ['redis://r1.docker', 'redis://r2.docker'],
2846-
'report' => 'semaphore',
2847-
],
2796+
'lock' => '%env(LOCK_DSN)%',
28482797
]);
28492798
2799+
.. seealso::
2800+
2801+
For more details, see :doc:`/lock`.
2802+
28502803
.. _reference-lock-resources-name:
28512804

28522805
name

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.