如果它冻结,我该如何重启php脚本?

时间:2012-10-05 12:30:47

标签: php shell concurrency parallel-processing cron

它运行“某种deamon”。

实际上我的bootstrap文件如下所示:

<?
$command = "php -f httpdocs/shell/run.php -- -job search/updater::run";
while(true) {
  passthru($command);
}

不幸的是,passthru之后发生的事情涉及到一些严重错误的东西,并且从某个时候图书馆冻结了。我使用tick函数进行了调试,结果发现它在外部http资源上有某种等待while(!feof ....

但是我想调度进程以及while循环完成触摸文件的所有内容。

当时间戳过时,我想终止进程并重新启动它。

然而passthru是阻塞的,所以它不会在那个脚本中到达那里。

我需要以某种方式将它分发到后台并有一个循环,它会持续监视它是否仍在运行或文件修改时间戳是否过时并杀死旧进程并启动一个新进程,或者只是启动一个新进程。

我该怎么做?还是有更好/更简单的解决方案?

2 个答案:

答案 0 :(得分:1)

我不久前在命令行脚本上做了一个失速检测。听起来有些事情需要发生......

1)在您正在运行的命令中为http://请求添加超时

2)您可以使用while()语句对其进行监控,您必须使用以下内容:

$stillRunning = true;
while ($stillRunning) {
    exec('ps -ef | grep httpdocs/shell/run.php', $processes); //will get all process which contain the path to the file

    //loop through all processes to determine if it's still running.  If so, grab the process ID and kill it'

    exec('kill '.$processId);

    //if it's still there, this will do the job
    if ($this->_ifProcessExists($processId)) {
        exec('kill -9 '.$processId);
    }

    sleep(2);
}

这是我为检测失速而建立的课程,以满足我们的需求......

<?php
/**
 * GMC Management Class
 * 
 */

class GMC {

    private $executablePath = '/usr/local/PNetT/PNetTCNetClient',
            $outPath = '/usr/local/PNetT/tmpData/SOB/',
            $workflowPath = '',
            $graphicPath = '',
            $logRecipient = 'my@email.com',
            $stalledThreshold = 10, //in seconds
            $originalProcesses = array(),
            $processes = array(),
            $log = array();

    public function __construct () {
        $this->workflowPath = $this->outPath.'workflows/';
        $this->graphicPath = $this->outPath.'graphics/';
    }

    /**
     * Adds an image to the GMC graphics directory
     * 
     * @param string $imgPath The absolute path of the image to add
     */
    public function addImage ($imgPath) {
        exec('cp '.$imgPath.' '.$this->graphicPath);
    }

    /**
     * Determines if a process is stalled
     */
    public function isStalled ($processes = false) {
        if ($processes === false) {
            $processes = $this->_getProcesses();
            $this->originalProcesses = $processes;
        }

        foreach ($processes as $process) {
            if (array_key_exists('duration', $process) && $process['duration'] <= (time() - $this->stalledThreshold)) {
                $this->_addLog("detected #".$process['processId']." as a stalled process");
                return true;
            }
        }

        return false;
    }

    /**
     * Fixes GMC's being stalled
     * Will also report the document that caused the stall
     */
    public function fixStalled () {
        $this->_restart();

        $this->reportLog();
    }

    /**
     * Sends the log to the development team for review
     */
    public function reportLog () {
        $body = "Here's a report how GMC was handled during this last stall:

Oldest process:\n
        ID | COMMAND\n";

        $oldest = $this->_getOldestProcess();
        $body .= "        ".$oldest['processId']." | ".$oldest['command']."\n";

        $body .= "
Logs:\n";

        foreach ($this->log as $log) {
            $body .= "        ".$log."\n";
        }

        $body .= "
Processes:\n
        ID | COMMAND\n";

        foreach ($this->processes as $process) {
            $body .= "        ".$process['processId']." | ".$process['command']."\n";
        }

        mail($this->logRecipient, 'GMC Stalled Report', $body);
    }

    /**
     * Restarts GMC
     * Must be conducted after GMC's stalled processes have been killed
     */
    private function _restart () {
        //kill all GMC processes
        foreach ($this->_getProcesses(true) as $process) {
            $this->_killProcess($process['processId']);
        }

        //restart GMC
        exec('bash /usr/local/PNetT/pnet.sh');

        $this->_addLog("GMC has been restarted");
    }

    /**
     * Restarts GMC
     * Must be conducted after GMC's stalled processes have been killed
     */
    private function _getOldestProcess () {
        $oldest = array(
            'timestamp' => 0,
            'processId' => 0
        );
        foreach ($this->_getProcesses() as $process) {
            if ($process['user'] == 'wwwuser' && $process['duration'] > $oldest['timestamp']) {
                $oldest = array(
                    'timestamp' => $process['duration'],
                    'processId' => $process['processId']
                );
            }
        }

        return $this->processes[$oldest['processId']];
    }

    /**
     * Get a list of all GMC processes
     */
    private function _getProcesses ($newList = false) {
        if ($newList == true || count($this->processes) == 0) {
            //exec('ps -ef | grep GMC', $processes);
            //sample processes for testing, above command is for live usage
            $processes = array(
                'ps -ef | grep GMC',
                'wwwuser   1767 31199  0 12:40 ?        00:00:00 /scripts/GMC/PNetT-5.1-SP1/PNetTCNetClient.bin -o /usr/local/PNetT/tmpData/SOB/workflows/master_ppo_sob_3col.wfd -e PDF -f /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP_temp.pdf -useincluded * -difDataInput1 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP.txt -difDataInput2 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP-table.txt',
                'wwwuser   2364  1207  0 12:41 ?        00:00:00 /scripts/GMC/PNetT-5.1-SP1/PNetTCNetClient.bin -o /usr/local/PNetT/tmpData/SOB/workflows/master_ppo_sob_3col.wfd -e PDF -f /usr/local/PNetT/tmpData/SOB/Master PPO-LP2045 mock up_temp.pdf -useincluded * -difDataInput1 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2045 mock up.txt -difDataInput2 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2045 mock up-table.txt',
                'wwwuser   2465  2378  0 12:42 ?        00:00:00 /scripts/GMC/PNetT-5.1-SP1/PNetTCNetClient.bin -o /usr/local/PNetT/tmpData/SOB/workflows/master_ppo_sob_3col.wfd -e PDF -f /usr/local/PNetT/tmpData/SOB/Master PPO-PBARR Test 12-20_temp.pdf -useincluded * -difDataInput1 /usr/local/PNetT/tmpData/SOB/Master PPO-PBARR Test 12-20.txt -difDataInput2 /usr/local/PNetT/tmpData/SOB/Master PPO-PBARR Test 12-20-table.txt',
                'wwwuser  19370  7900  0 13:17 ?        00:00:00 /scripts/GMC/PNetT-5.1-SP1/PNetTCNetClient.bin -o /usr/local/PNetT/tmpData/SOB/workflows/master_ppo_sob_3col.wfd -e PDF -f /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069_temp.pdf -useincluded * -difDataInput1 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069.txt -difDataInput2 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069-table.txt',
                'root     19948 19508  0 13:18 pts/6    00:00:00 grep GMC',
                'wwwuser  26685 17061  0 12:25 ?        00:00:00 /scripts/GMC/PNetT-5.1-SP1/PNetTCNetClient.bin -o /usr/local/PNetT/tmpData/SOB/workflows/diff_report.wfd -e PDF -f /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP_differences.pdf -useincluded * -difDataInput1 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP-report.txt -difDataInput2 /usr/local/PNetT/tmpData/SOB/Master PPO-LP2069 Solution PPO 1500-15-20 MOCKUP-table-report.txt',
                'root     32017     1 89 May03 ?        12-18:02:22 /scripts/GMC/PNetT-5.1-SP1/PNetTNetServer.bin -tempdir /usr/local/GMC/PNetT-5.1-SP1/tmpData -D'
            );

            $this->processes = array();
            foreach ($processes as $idx => $process) {
                if ($idx > 1) {
                    $pieces = preg_split("/\s+/", $process, 8);

                    //skip the grep filter process
                    if ($pieces[7] != 'grep GMC') {
                        $this->processes[$pieces[1]] = array(
                            'user' => $pieces[0],
                            'processId' => $pieces[1],
                            'duration' => strtotime($pieces[4]),
                            'command' => $pieces[7]
                        );
                    }
                }
            }
        }

        return $this->processes;
    }

    /**
     * Kills a process
     * 
     * @param int $processId The process to be killed
     */
    private function _killProcess ($processId) {
        //nicely
        exec('kill '.$processId);

        //if it's still there, this will do the job
        if ($this->_ifProcessExists($processId)) {
            exec('kill -9 '.$processId);

            $this->_addLog("process #".$processId." wasn't nicely killed, I had to force it");
        } else {
            $this->_addLog("process #".$processId." was nicely killed");
        }
    }

    /**
     * Determines if a process is still running
     * 
     * @param int $processId The process to be checked
     */
    private function _ifProcessExists ($processId) {
        exec('ps '.$processId, $return);

        return count($return) > 1;
    }

    /**
     * Adds a message to the log
     */
    private function _addLog ($message) {
        $this->log[] = $message;
    }
}

?>

答案 1 :(得分:0)

实际上解决问题更好,而不是解决问题。 就我而言,我正在处理第三方代码。然而phps tick处理函数让我有可能找到正确的代码部分,问题在php.net主页上是一个很大的警告,以及解决方案。

它与超时无关,但与断开的套接字上的此功能有关。

  

警告如果fsockopen()打开的连接未被关闭   服务器,feof()将挂起。要解决此问题,请参阅以下示例:

     

示例#1使用feof()处理超时      

返回feof($ fp); }

     

/ *假设$ fp先前由fsockopen()* /

打开      

$ start = NULL; $ timeout = ini_get('default_socket_timeout');

     

while(!safe_feof($ fp,$ start)&amp;&amp;(microtime(true) - $ start)&lt;   $ timeout){/ *句柄* /}?&gt;