如何一次只运行一次脚本并获取当前运行脚本的列表?

时间:2013-05-24 13:56:38

标签: php cron locking

短篇小说:

我有一个名为(cron_mailings.php)的脚本,我需要知道它是否正在运行。是否有函数或变量如$ _SERVER来获取当前脚本(cron_mailings.php)的实例数? 因为我不希望脚本在任何给定时刻运行多次。

长篇故事:

我们有cron job调用脚本列表,其中一个脚本是(cron_mailings.php)。 cron_mailings.php转到mailings表,获取电子邮件记录列表 - 首先是100 - 然后从表中发送和删除它们。稍后,cron job将再次执行,并致电cron_mailings.php,以处理接下来的100封电子邮件。

问题是,有人错误地设置了cron作业,上周它在5秒内运行了6次并且我们有一个典型的Race Condition,第一个实例获得了前100个用户,而它正在处理用户#10的另一个实例cron job调用了相同的脚本,cron_mailings运行并获取了100个用户。现在,两个脚本都与90个用户重叠,这些用户两次收到同一封邮件。

我们已经修复了cron工作,但以防我必须找到解决方案,因为我不知道将来会使用该脚本,所以

我实施了两个解决方案:

  1. 将字段标志添加到名为mailings的db is_fetched表中(1表示已取,0 除此以外)。并设置cron_mailings.php以仅获取标记的记录 with is_fetched = 0。通过该解决方案不止一次的实例 scrip实际上可以在表的不同部分运行和工作 。例如。 first instance调用前100条记录并将1分配给 is_fetched,另一个实例将来到第二个100 记录其中is_fetched = 0并处理它们。

  2. 通过在db表中放置一个标志以了解脚本是否正在运行来阻止整个脚本,然后在脚本顶部执行以下操作:

    check if (is_cron_maillings_running() === 'Y')
    {
        die("script is running at the moment");
    }
    else
    {
        set_is_cron_maillings_running("Y");
        // do some stuff - send emails and save the world
        //1
        //.
        //.
        //10
        set_is_cron_maillings_running("N");
    }
    
  3. 两种解决方案都很好(基本上第二种解决方案会胜过第一种解决方案)

    但我有一个问题:

    如果在到达最后一行set_is_cron_maillings_running("N");之前脚本在步骤1和10之间死亡/崩溃/错误抛出/ db服务器消失/ .etc怎么办? cron作业调用的任何其他脚本将在db表中看到is_cron_maillings_running = Y并且永远不会再次执行,除非有人手动将值重新分配给N.

    对于找到更好的锁定脚本方法的建议,我非常开放。到目前为止,在我看来,我认为如果我设法从服务器获取运行脚本列表(搜索当前脚本是否正在运行),这比为db表无法真正完全执行的db表分配值更安全并且分配正在运行= N.

1 个答案:

答案 0 :(得分:1)

不是在锁定文件/字段中存储Y / N,而是在设置锁定时存储日期(Y),或者在没有锁定(N)时存储空值。然后,如果该日期超过X时间量,请忽略它。这样一旦出现问题,一旦锁定失效,您的脚本将再次开始工作。