Предотвращение многократного выполения консольной команды

Дата обновления перевода 2024-07-17

Предотвращение многократного выполения консольной команды

Простой, но эффективный способ предотвращения многократного выполнения одной и той же команды на одном сервере заключается в использовании блокировок. Компонент Блокировка предоставляет множество классов для создания замков, основанных на файловой системе (FlockStore ), общей памяти (SemaphoreStore ) и даже DB и серверах Redis.

В дополнение, компонент Консоль предоставляет PHP-черту под названием LockableTrait, которая добавляет два удобных метода для блокировки и выпуска команд:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\LockableTrait;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class UpdateContentsCommand extends Command
{
    use LockableTrait;

    // ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        if (!$this->lock()) {
            $output->writeln('The command is already running in another process.');

            return Command::SUCCESS;
        }

        // Если вы предпочитаете дождаться выпуска замка, используйте:
        // $this->lock(null, true);

        // ...

        // если выпуск неясный, Symfony выпускает замок автоматически,
        // когда заканчивается выполнение команды
        $this->release();

        return Command::SUCCESS;
    }
}

LockableTrait будет использовать SemaphoreStore, если он доступен, и вариант по умолчанию - FlockStore, в противном случае. Вы можете переопределить это поведение, задав свойство $lockFactory с вашей собственной фабрикой блокировок:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\LockableTrait;
use Symfony\Component\Lock\LockFactory;

class UpdateContentsCommand extends Command
{
    use LockableTrait;

    public function __construct(private LockFactory $lockFactory)
    {
    }

    // ...
}

7.1

Свойство $lockFactory было представлено в Symfony 7.1.