【问题标题】:Using a file lock to ensure a PHP Daemon script is only running once使用文件锁确保 PHP 守护程序脚本只运行一次
【发布时间】:2019-01-11 04:25:32
【问题描述】:

我写了一个简单的函数,用来判断一个脚本是否已经在运行,并防止重复进程:

class SomeClass{
  public static function processLock($name)
  {
    $lockFile = "/tmp/" . $name;
    $fp       = fopen($lockFile, "w+");

    if ($fp === false)
    {
      echo "Already running.\n";
      exit;
    }
    else
    {
      if ( ! flock($fp, LOCK_EX | LOCK_NB))
      {
        echo "Already running.\n";
        exit;
      }
    }

    return $fp;
  }
}

然后我可以在 php 脚本的顶部调用这样的函数:

脚本_A:

<?

include_once "/SomeClass.php";

$lock = SomeClass::processLock("script_A_lock");

这很好用...... 99% 的时间。但是,有时我会发现“script_A”没有运行(它应该一直在运行)。

然后我运行lsof /tmp/script_A_lock 来查看为什么“script_A”没有启动。

结果毫无意义!我得到这样的东西:

COMMAND    PID     .........     NAME
Script_B   234     .........     script_A_lock

一个不相关的脚本“script_B”不知何故窃取了文件锁!

所以:

  1. 这是怎么回事? “script_A_lock”这个词只出现在 Script_A 中(我搜索了整个项目)并且 Script_A 不包括在任何地方。
  2. 如何防止这种情况发生?显然,只有脚本 A 应该持有“script_A_lock”。

【问题讨论】:

    标签: php command-line-interface daemon


    【解决方案1】:

    这是我通常用于锁定文件的方法。如果该文件不存在,则创建它,这表明该进程正在执行。请务必在最后取消链接。

    #!/usr/bin/php
    <?php
    define('LOCK_FILE',__FILE__.'lock');
    if (!is_file(LOCK_FILE)) {
        touch(LOCK_FILE);
        echo 'Do stuff'.PHP_EOL;
        unlink(LOCK_FILE);
    } else {
        echo 'Lock file found'.PHP_EOL;
    }
    

    flock 函数旨在支持多个脚本访问单个文件,并不意味着将其用作锁定文件。 http://php.net/manual/en/function.flock.php

    【讨论】:

    • flock 函数适用于共享锁和排他锁。只需使用LOCK_EX 使其独占即可。 (请参阅您链接到的文档)
    • 此方法不适用于守护程序脚本,因为您不能“在最后取消链接”。我希望脚本无限期地运行。如果 / 当脚本结束时,它会意外地这样做。
    • 然后你可以把 unlink 放在 register_shutdown_function secure.php.net/manual/en/…
    猜你喜欢
    • 1970-01-01
    • 2017-04-19
    • 2011-08-20
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    相关资源
    最近更新 更多