【问题标题】:Make sure one copy of php script running in background确保一份 php 脚本在后台运行
【发布时间】:2013-05-05 21:17:00
【问题描述】:

我正在使用 cronjob 来运行每 1 分钟执行一次的 php 脚本

我还需要确保只有副本正在运行,因此如果此 php 脚本在 2 分钟后仍在运行,则 cronjob 不应运行另一个版本。

目前我有 2 个选项,我想看看您的反馈,如果您还有其他选项

选项 1:在 php 脚本启动时创建一个 tmp 文件,并在 php 脚本完成时将其删除(并检查文件是否存在)---> 这个选项对我来说的问题是,如果我的 php 脚本崩溃不管什么原因,它都不会再次运行(tmp文件不会被删除)

选项 2:运行如下所示的 bash 脚本来控制 php 脚本的执行 ---> 很好,但正在寻找可以在 php 中完成的事情

#!/bin/bash
function rerun {
        BASEDIR=$(dirname $0)
        echo $BASEDIR/$1
        if ps -ef | grep -v grep | grep $1; then
            echo "Running"
            exit 0
    else
            echo "NOT running";
            /usr/local/bin/php $BASEDIR/$1 &
            exit $?
    fi

}  
rerun myphpscript.php

PS:我刚刚在http://www.php.net/manual/en/class.mutex.php 看到了“Mutex class”,但不确定它是否稳定并且有人尝试过。

【问题讨论】:

  • 您可以在 php 中执行大部分 bash 脚本,方法是进入 shell 运行 1 个命令来检查进程是否正在运行
  • 是的,我可以这样做,但它再次只是 php 中的 shell :)
  • PHP 在不进入 shell 的情况下对操作系统的访问受到限制。许多其他应用程序使用锁/进程 ID 文件来管理自己
  • Calling cron twice or triple sometimes 的可能重复项。可以以多种方式实现用于控制(或避免)并行执行的排他锁。一个常见的解决方案是简单地在 PHP 中创建一个空文件,检查它是否已经存在,并在脚本完成后将其删除。

标签: php background cron mutex


【解决方案1】:

您可能想使用我的库ninja-mutex,它提供了简单的接口来处理互斥锁。目前可以使用flock、memcache、redis或mysql来处理锁。

下面是一个使用memcache的例子:

<?php
require 'vendor/autoload.php';

use NinjaMutex\Lock\MemcacheLock;
use NinjaMutex\Mutex;

$memcache = new Memcache();
$memcache->connect('127.0.0.1', 11211);
$lock = new MemcacheLock($memcache);
$mutex = new Mutex('very-critical-stuff', $lock);
if ($mutex->acquireLock(1000)) {
    // Do some very critical stuff

    // and release lock after you finish
    $mutex->releaseLock();
} else {
    throw new Exception('Unable to gain lock!');
}

【讨论】:

    【解决方案2】:

    我经常在我的 crontab 中直接使用许多 Linux 发行版附带的程序 flock,例如:

    * * * * * flock -n /var/run/mylock.LCK /usr/local/bin/myprogram
    

    当然,如果您手动启动 myprogram 的两个实例,实际上仍然可以同时启动,但 crond 只会创建一个。

    Flock 是一个小型编译二进制文件,与最终更大的 php 代码块相比,它的启动速度非常快。如果您有许多运行时间更长的执行,这尤其有好处,而您实际上并不完全清楚。

    【讨论】:

    • 这是这个问题的标准答案。
    【解决方案3】:

    如果您不在 NFS 挂载上,则可以使用 flock() (http://php.net/manual/en/function.flock.php):

    $fh = fopen('guestbook.txt','a')         or die($php_errormsg);
    $tries = 3;
    while ($tries > 0) {
        $locked = flock($fh,LOCK_EX | LOCK_NB);
        if (! $locked) {
            sleep(5);
            $tries--;
        } else {
            // don't go through the loop again 
            $tries = 0;
        }
    }
    if ($locked) {
        fwrite($fh,$_REQUEST['guestbook_entry']) or die($php_errormsg);
        fflush($fh)                              or die($php_errormsg);
        flock($fh,LOCK_UN)                       or die($php_errormsg);
        fclose($fh)                              or die($php_errormsg);
    } else {
        print "Can't get lock.";
    }  
    

    发件人:http://docstore.mik.ua/orelly/webprog/pcook/ch18_25.htm

    【讨论】:

      【解决方案4】:

      我发现对我来说最好的解决方案是为您的脚本创建一个单独的数据库用户,并将该用户的并发连接限制为 1。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        相关资源
        最近更新 更多