i upgraded recently to Symfony 3.4.x, refactor LockHandler because of deprecation warning and fall into strange behaviour.
Code in command before refactoring:
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:
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
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(); }