Skip to content

Commit 5b1b7b6

Browse files
committed
[Console] Add documentation about the AsLockedCommand attribute
1 parent a183601 commit 5b1b7b6

File tree

2 files changed

+112
-46
lines changed

2 files changed

+112
-46
lines changed

console/lockable_command.rst

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
Prevent Running the Same Console Command Multiple Times
2+
=======================================================
3+
4+
You can use `locks`_ to prevent the same command from running multiple times on
5+
the same server. The :doc:`Lock component </components/lock>` provides multiple
6+
classes to create locks based on the filesystem (:ref:`FlockStore <lock-store-flock>`),
7+
shared memory (:ref:`SemaphoreStore <lock-store-semaphore>`) and even databases
8+
and Redis servers.
9+
10+
Using the AsLockedCommand attribute
11+
-----------------------------------
12+
13+
The Console component provides an attribute called ``AsLockedCommand`` that automatically
14+
sets a lock on your command, and release it when the command ends::
15+
16+
// ...
17+
use Symfony\Component\Console\Attribute\AsLockedCommand;
18+
use Symfony\Component\Console\Command\Command;
19+
use Symfony\Component\Console\Input\InputInterface;
20+
use Symfony\Component\Console\Output\OutputInterface;
21+
22+
#[AsLockedCommand(
23+
name: 'app:database:purge',
24+
)]
25+
class PurgeDatabaseCommand extends Command
26+
{
27+
protected function execute(InputInterface $input, OutputInterface $output): int
28+
{
29+
$output->writeln('Purging the database...');
30+
31+
return Command::SUCCESS;
32+
}
33+
}
34+
35+
.. versionadded:: 7.1
36+
37+
The ``AsLockedCommand`` attribute was introduced in Symfony 7.1.
38+
39+
By default, the command name will be use as a key for the lock, but you can customize it::
40+
41+
use Symfony\Component\Console\Attribute\AsLockedCommand;
42+
use Symfony\Component\Console\Command\Command;
43+
44+
#[AsLockedCommand(
45+
name: 'app:database:purge',
46+
lock: 'my-custom-lock-key',
47+
)]
48+
class PurgeDatabaseCommand extends Command
49+
{
50+
// ...
51+
}
52+
53+
If, for any reason, you need to define the lock key at runtime, you can define it with a callable::
54+
55+
use Symfony\Component\Console\Attribute\AsLockedCommand;
56+
use Symfony\Component\Console\Command\Command;
57+
use Symfony\Component\Console\Input\InputInterface;
58+
59+
#[AsLockedCommand(
60+
name: 'app:database:purge',
61+
lock: [self::class, 'getLockKey'],
62+
)]
63+
class PurgeDatabaseCommand extends Command
64+
{
65+
// ...
66+
67+
public static function getLockKey(InputInterface $input): string
68+
{
69+
return $input->getArgument('lock-key');
70+
}
71+
}
72+
73+
Using the LockableTrait
74+
-----------------------
75+
76+
In addition, the Console component provides a PHP trait called ``LockableTrait``
77+
that adds two convenient methods to lock and release commands::
78+
79+
// ...
80+
use Symfony\Component\Console\Command\Command;
81+
use Symfony\Component\Console\Command\LockableTrait;
82+
use Symfony\Component\Console\Input\InputInterface;
83+
use Symfony\Component\Console\Output\OutputInterface;
84+
85+
class UpdateContentsCommand extends Command
86+
{
87+
use LockableTrait;
88+
89+
// ...
90+
91+
protected function execute(InputInterface $input, OutputInterface $output): int
92+
{
93+
if (!$this->lock()) {
94+
$output->writeln('The command is already running in another process.');
95+
96+
return Command::SUCCESS;
97+
}
98+
99+
// If you prefer to wait until the lock is released, use this:
100+
// $this->lock(null, true);
101+
102+
// ...
103+
104+
// if not released explicitly, Symfony releases the lock
105+
// automatically when the execution of the command ends
106+
$this->release();
107+
108+
return Command::SUCCESS;
109+
}
110+
}
111+
112+
.. _`locks`: https://en.wikipedia.org/wiki/Lock_(computer_science)

console/lockable_trait.rst

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)