i upgraded recently to Symfony 3.4.x, refactor LockHandler because of deprecation warning and fall into strange behaviour.
Code in command before refactoring:
JavaScript
x
class FooCommand
{
protected function configure() { /* ... does not matter ... */ }
protected function lock() : bool
{
$resource = $this->getName();
$lock = new SymfonyComponentFilesystemLockHandler($resource);
return $lock->lock();
}
protected function execute()
{
if (!$this->lock()) return 0;
// Execute some task
}
}
And it prevents to run two command at the same time – second just finishes without doing job. That is good.
But after suggested refactoring it allows to run many commands simultaneously. This is FAIL. How to prevent execution? New code:
JavaScript
class FooCommand
{
protected function configure() { /* ... does not matter ... */ }
protected function lock() : bool
{
$resource = $this->getName();
$store = new SymfonyComponentLockFlockStore(sys_get_temp_dir());
$factory = new SymfonyComponentLockFactory($store);
$lock = $factory->createLock($resource);
return $lock->acquire();
}
protected function execute()
{
if (!$this->lock()) return 0;
// Execute some task
}
}
NB #1: I don’t care about many servers or so, just one instance of application.
NB #2: If process was killed then new command must unlock and run.
Advertisement
Answer
You must use the LockableTrait trait
JavaScript
use SymfonyComponentConsoleCommandLockableTrait;
use SymfonyComponentConsoleCommandCommand
class FooCommand extends Command
{
use LockableTrait;
..
protected function execute(InputInterface $input, OutputInterface $output)
{
if (!$this->lock()) {
$output->writeln('The command is already running in another process.');
return 0;
}
// If you prefer to wait until the lock is released, use this:
// $this->lock(null, true);
// ...
// if not released explicitly, Symfony releases the lock
// automatically when the execution of the command ends
$this->release();
}