On Symfony 4.4, I am trying to establish a lock in a command and keep it alive until explicitly released. Reading the docs I understand that this should be obtained with the $autoRelease
param of Symfony\Component\Lock\LockFactory::createLock()
, but it seems that even if I set $autoRelease = false
the lock is automatically released when the script ends.
LockCommand
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Lock\LockFactory;
class LockCommand extends Command
{
const LOCK_NAME = "my_lock";
protected static $defaultName = 'app:lock';
private $lockFactory;
public function __construct(LockFactory $lockFactory)
{
$this->lockFactory = $lockFactory;
parent::__construct();
}
protected function configure()
{
$this
->setDescription("Enables/disables the lock.")
->addOption(
'release',
'r',
InputOption::VALUE_NONE,
'Releases the lock'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$lock = $this->lockFactory->createLock(self::LOCK_NAME, 300.0, false);
$release = $input->getOption('release');
if ($release) {
$lock->release();
} else {
$lock->acquire();
}
//sleep(300);
return 0;
}
}
LockVerifyCommand
<?php
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Lock\LockFactory;
class LockVerifyCommand extends Command
{
protected static $defaultName = 'app:lock-verify';
private $lockFactory;
public function __construct(LockFactory $lockFactory)
{
$this->lockFactory = $lockFactory;
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$lock = $this->lockFactory->createLock(LockCommand::LOCK_NAME, 300.0, false);
$status = $lock->acquire() ? "no" : "yes";
$output->writeln("Locked? $status");
return 0;
}
}
I would expect to be able to
- enable the lock
php bin/console app:lock
php bin/console app:lock-verify
should sayLocked? yes
- until I release the lock
php bin/console app:lock --release
this happens only while the app:lock
command is running.
CodePudding user response:
The most important thing here is the actual implementation of LockStore
. Depending on which one you choose can mean a whole lot of difference.
For example, if I am not mistaken, the LockStore is SemaphoreStore
by default. You can look up the code on GitHub, but the main thing to notice is that it uses PHP's ext-semaphore
extension (that is, sem_*
functions). Looking into the PHP's doc page for sem_acquire
, it says:
After processing a request, any semaphores acquired by the process but not explicitly released will be released automatically and a warning will be generated.
In other words, the lock is not persisted after the main process ends.
The same goes for FileStore
, though it is entirely up to OS to release the lock, which can get messy.
What you need is some persistent store, like PdoStore
, DoctrineDbalStore
, RedisStore
, or something else.
Just beware that some stores auto-expire locks. You can read more about that in the official docs page: Expiring Locks