不要运行一个cron php任务,直到最后一个完成

时间:2014-05-31 14:10:17

标签: php linux bash concurrency cron

我有一个php-cli脚本,cron5 minutes运行一次。由于此间隔很短,因此multiple processes同时运行。这不是我想要的,因为这个脚本必须在文本文件中写入一个每次递增的数字id。碰巧writers正在同时写入此文本文件,并且写入的值不正确。

我曾尝试使用php的flock函数阻止在文件中写入,当另一个进程正在写入但它不起作用时。

$fw = fopen($path, 'r+');
if (flock($fw, LOCK_EX)) {
    ftruncate($fw, 0);
    fwrite($fw, $latestid);
    fflush($fw);
    flock($fw, LOCK_UN);
}
fclose($fw);

所以我想这个解决方案是创建一个bash脚本来验证是否有一个正在运行的php script实例,如果是,它应该等到它完成。但我不知道怎么做,有什么想法吗?

5 个答案:

答案 0 :(得分:3)

我真的不明白每5分钟增加一个计数器会导致多个进程同时尝试写入计数器文件,但是......

更简单的方法是使用类似于下面的简单锁定机制:

<?php

$lock_filename = 'nobodyshouldincrementthecounterwhenthisfileishere';

if(file_exists($lock_filename)) {
  return;
}

touch($lock_filename);

// your stuff...

unlink($lock_filename);

这是一个简单的方法,它不会处理脚本在删除锁定文件之前中断的情况,在这种情况下,它会在删除之前再次运行。

如您所建议的那样,也可以采用更复杂的方法,例如:在自己的进程中分配作业,将PID写入文件,然后在运行作业之前,可以检查PID是否仍在运行。

答案 1 :(得分:3)

我与bash script一起使用的解决方案是:

exec 9>/path/to/lock/file
if ! flock -n 9  ; then
    echo "another instance is running";
    exit 1
fi
# this now runs under the lock until 9 is closed (it will be closed automatically when the script ends)  

文件描述符9>/var/lock/file中创建,flock将退出尝试运行的新进程,除非脚本中没有其他实例在跑。

How can I ensure that only one instance of a script is running at a time (mutual exclusion)?

答案 2 :(得分:0)

不是每隔5分钟使用cron来运行脚本,而是在完成后5分钟使用at来安排脚本再次运行。在脚本结束时,您可以使用shell_exec()运行at命令来安排脚本在5分钟内再次运行,如下所示:

at now + 5 minutes /path/to/script

答案 3 :(得分:0)

或者,甚至可能比我之前的答案更简单(使用at安排脚本在5分钟内再次运行)通过使用非终止循环使您的脚本成为守护程序,如下所示:

while(1) {
  // whatever your script does here....
  sleep(300) //wait 5 minutes
}

然后,您可以完全取消cronat的排程。只需从命令行在后台运行脚本,如下所示:

/path/to/your/script &

或者,在/etc/rc.local中添加/path/to/your/script以使您的脚本在计算机启动时自动启动。

答案 4 :(得分:0)

为防止在上一个会话仍在运行之前启动任何程序的下一个会话,例如下一个cron作业,我建议使用内置于程序中或外部检查此程序的运行过程。只需在开始程序之前执行

 ps -ef|grep <process_name>|grep -v grep|wc -l

并检查,如果结果为0.只有在这种情况下才可以启动程序。 我想,您必须保证缺少具有相似名称的第三方流程。 (为此目的,为您的程序提供更长且唯一的名称)。并且程序的名称不得包含“grep”模式。

这项工作很好地与cron守护程序在cron表中配置的程序的正常常规启动相结合。 对于将检查写为外部脚本的情况,crontab中的条目可能类似于

 <time_specification>  <your_starter_script>  <your_program> ...

2个重要说明:如果没有启动程序,your_starter_script的退出代码必须为0,最好完全禁止通过此脚本写入stdout或stderr。

这种启动器非常简短,只需简单的编程练习。因此,我觉得不需要提供完整的代码。