【发布时间】:2013-01-01 06:02:00
【问题描述】:
我有一堆 php 脚本计划在 CentOS 机器上的 cron 中每隔几分钟运行一次。我希望每个脚本在启动时自行检查它的前一个实例是否仍在运行,如果是则停止。
【问题讨论】:
-
使用下面提到的锁文件,或者使用数据库,它可以比锁文件做更多的事情,例如存储统计:开始/停止时间,手动cron启动,它也支持锁定。
我有一堆 php 脚本计划在 CentOS 机器上的 cron 中每隔几分钟运行一次。我希望每个脚本在启动时自行检查它的前一个实例是否仍在运行,如果是则停止。
【问题讨论】:
我这样做是为了管理任务并确保它们一次只运行一个
public function startTask($taskname)
{
$running = "running";
$lockfile = $taskname . "RUNNING";
file_put_contents($lockfile, $running);
}
public function endTask($taskname)
{
$lockfile = $taskname . "RUNNING";
unlink($lockfile);
}
public function isTaskRunning($taskname)
{
$lockfile = $taskname . "RUNNING";
if (file_exists($lockfile))
{
return true;
}
}
您在开始任务时调用startTask('name'),然后在完成时调用endTask('name')。在你使用的任务的第一行
if (isTaskRunning('name')) {
die('already running');
}
将这些放在配置类或所有任务文件中包含的东西中
【讨论】:
使用锁定文件:
<?php
$lockfile = "/tmp/lock.txt";
$fp = fopen($lockfile, "r+");
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
ftruncate($fp, 0); // truncate file
fwrite($fp, sprintf("Started: %s\nPID: %s", date(), getmypid()));
// perform your tasks here.
fflush($fp); // flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't get the lock!\nCheck $lockfile for more info.";
}
fclose($fp);
【讨论】:
或者,如果您使用的是数据库,您可以像这样创建数据库Named Lock:
<?php
$process = "myProcess";
$sql = mysql_query("select get_lock('$process', 0)");
$got_lock = (bool)mysql_fetch_array($sql)[0];
// If process is already running exit
if(!$got_lock){
echo "Process running";
exit;
}
// Run my process
for($i=0;$i<100000000;$i++){
echo $i;
}
// Release the lock
mysql_query("select release_lock('$process')");
这种形式的锁定称为named lock,它不会“锁定”数据库,它只是创建一个“命名锁定”,当您调用它时,它会检查名称是否存在。它与table lock 或row lock 完全不同,它内置于mysql 中,用于其他应用程序,例如this。
您可以拥有任意数量的锁,一旦应用程序结束,它们就会自动释放,例如您的客户端与 mysql 断开连接:进程完成、php 中断/崩溃、mysql 崩溃(这不是 100% 确定)等。
【讨论】:
您可以在 PHP 脚本的末尾添加一个简单的回显(可能带有 date()),这将在您的 cron 日志中可见,并显示脚本是否到达末尾(然后完成其任务)
【讨论】: