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 控制台命令的助手。它只实现了两个锁定存储,它们都是本地的。它们是FlockStoreSemaphoreStore 商店。这不适用于MemcachedStoreRedisStore。如果需要后者中的任何一个商店,那么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 锁定组件不锁定——如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

Oracle账号被锁定如何解锁

如何解锁DB2中被锁定的表

ORACLE 如何查询被锁定表及如何解锁释放session

ORACLE 如何查询被锁定表及如何解锁释放session

电脑的监控控制锁如何解锁

如何实时监测域账号锁定及锁定邮件通知和邮件解锁?