Symfony 锁定组件不锁定——如何解决?
Posted
技术标签:
【中文标题】Symfony 锁定组件不锁定——如何解决?【英文标题】:Symfony Lock Component does not lock – how to fix? 【发布时间】:2018-05-26 05:35:55 【问题描述】:我最近升级到 Symfony 3.4.x,由于弃用警告而重构 LockHandler 并陷入奇怪的行为。
重构前的命令代码:
class FooCommand
protected function configure() /* ... does not matter ... */
protected function lock() : bool
$resource = $this->getName();
$lock = new \Symfony\Component\Filesystem\LockHandler($resource);
return $lock->lock();
protected function execute()
if (!$this->lock()) return 0;
// Execute some task
它可以防止同时运行两个命令——第二个只是完成而不做工作。这很好。
但是在建议重构之后,它允许同时运行许多命令。这是失败的。如何防止执行?新代码:
class FooCommand
protected function configure() /* ... does not matter ... */
protected function lock() : bool
$resource = $this->getName();
$store = new \Symfony\Component\Lock\FlockStore(sys_get_temp_dir());
$factory = new \Symfony\Component\Lock\Factory($store);
$lock = $factory->createLock($resource);
return $lock->acquire();
protected function execute()
if (!$this->lock()) return 0;
// Execute some task
注意 #1:我不关心很多服务器,只关心一个应用程序实例。
注意 #2:如果进程被终止,则必须解锁并运行新命令。
【问题讨论】:
【参考方案1】:您必须使用 LockableTrait 特征
use Symfony\Component\Console\Command\LockableTrait;
use Symfony\Component\Console\Command\Command
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();
【讨论】:
谢谢!效果很好。遗憾的是文档不包含此内容。 需要注意的是,LockableTrait
实际上只是 Symfony 控制台命令的助手。它只实现了两个锁定存储,它们都是本地的。它们是FlockStore
和SemaphoreStore
商店。这不适用于MemcachedStore
或RedisStore
。如果需要后者中的任何一个商店,那么LockableTrait
将无济于事。
感谢您注意到这一点!我看到了特质的来源——它真的很简单。就我而言,本地存储就足够了。【参考方案2】:
除了 Mohamed 的回答之外,为命令储物柜分配一个 id 很重要。
否则锁会出现与其他命令的并发问题,特别是如果您有不同的环境(测试、生产、阶段......)。您会看到该命令没有按预期的周期执行。
这个 id 可以在 lock()
语句本身上分配。
use Symfony\Component\Console\Command\LockableTrait;
use Symfony\Component\Console\Command\Command
class FooCommand extends Command
use LockableTrait;
.....
protected function execute(InputInterface $input, OutputInterface $output)
if (!$this->lock('FooCommand'.getenv('APP_ENV')))
$output->writeln('The command is already running in another process.');
return 0;
$this->release();
【讨论】:
以上是关于Symfony 锁定组件不锁定——如何解决?的主要内容,如果未能解决你的问题,请参考以下文章