如何检测PHP脚本是否已经在运行?

2022-08-30 22:35:09

我有一个cron脚本,每10分钟执行一个PHP脚本。该脚本检查队列并处理队列中的数据。有时,队列中有足够的数据来持续 10 分钟以上的处理,从而产生两个脚本尝试访问相同数据的可能性。我希望能够检测脚本是否已在运行,以防止启动脚本的多个副本。我想过创建一个数据库标志,说明脚本正在处理,但如果脚本崩溃,它会让它处于正状态。有没有一种简单的方法来判断PHP脚本是否已经在PHP或shell脚本中运行?


答案 1

您只能使用锁定文件。PHP的flock()函数为Unix的flock函数提供了一个简单的包装器,该函数为文件提供建议锁。

如果您没有明确释放它们,操作系统将在保存这些锁的进程终止时自动为您释放这些锁,即使它异常终止也是如此。

您还可以遵循松散的Unix约定,使您的锁定文件成为“PID文件” - 也就是说,在文件上获得锁定后,让您的脚本将其PID写入其中。即使您从未从脚本中读取过此内容,如果您的脚本挂起或发疯,并且您想要找到其PID以便手动杀死它,那对您来说也会很方便。

下面是一个复制/粘贴就绪的实现:

#!/usr/bin/php
<?php

$lock_file = fopen('path/to/yourlock.pid', 'c');
$got_lock = flock($lock_file, LOCK_EX | LOCK_NB, $wouldblock);
if ($lock_file === false || (!$got_lock && !$wouldblock)) {
    throw new Exception(
        "Unexpected error opening or locking lock file. Perhaps you " .
        "don't  have permission to write to the lock file or its " .
        "containing directory?"
    );
}
else if (!$got_lock && $wouldblock) {
    exit("Another instance is already running; terminating.\n");
}

// Lock acquired; let's write our PID to the lock file for the convenience
// of humans who may wish to terminate the script.
ftruncate($lock_file, 0);
fwrite($lock_file, getmypid() . "\n");

/*
    The main body of your script goes here.
*/
echo "Hello, world!";

// All done; we blank the PID file and explicitly release the lock 
// (although this should be unnecessary) before terminating.
ftruncate($lock_file, 0);
flock($lock_file, LOCK_UN);

只需将锁定文件的路径设置为您喜欢的任何位置即可。


答案 2

如果你运行的是 Linux,这应该在你的脚本顶部工作:

$running = exec("ps aux|grep ". basename(__FILE__) ."|grep -v grep|wc -l");
if($running > 1) {
   exit;
}

推荐