【问题标题】:How to get list of PHP processes running on server with PHP如何使用 PHP 获取在服务器上运行的 PHP 进程列表
【发布时间】:2013-06-24 12:44:05
【问题描述】:

我有一个运行 PHP 文件的 cronjob,该文件运行用 PHP 编写的 DAEMON,但我只想在没有其他实例运行的情况下运行 DAEMON,我怎样才能获得运行的 PHP 进程列表以便查找我的 DAEMON 是否正在运行。我想过某种 exec 会生成一个可以存储在数组中的列表。有任何想法吗?谢谢

【问题讨论】:

  • 最简单的方法可能是让守护进程使用进程 ID 创建一个 PID 文件,然后在每次脚本尝试创建新守护进程时检查该文件和 ID。如果您能展示如何创建守护进程,将会有所帮助。

标签: php process cron


【解决方案1】:

这是我使用 php 脚本控制 cron 的完整解决方案,该脚本包含 mysql db 用于配置和日志记录。您应该在源代码中找到问题的答案。

Cron_Job 类:

class Cron_Job
{

    /**
     * check if job is still running
     * @param int $pid
     * @return boolean
     */
    public function isJobRunning($pid)
    {
        try
        {
            $result = shell_exec(sprintf("ps %d", $pid));
            if (count(preg_split("/\n/", $result)) > 2)
            {
                return true;
            }
        } catch (Exception $e)
        {
        }

        return false;
    }

    /**
     * deletes job from run stack
     * @param int $pid
     */
    public function deleteRunningJob($pid)
    {
        $sql = "delete from croner_running_pids where pid = '$pid'";
        $ret = framework_Database::getInstance("****")->delete($sql);
    }

    /**
     * adds job into run stack
     * @param int $pid
     */
    public function addRunningJob($pid, $outputfile)
    {
        $sql = "insert into croner_running_pids (pid, `outfile`) values ('$pid', '$outputfile')";
        $id = framework_Database::getInstance("****")->insert_db($sql);
    }
}

类 Cron_Log:

class Cron_Log
{

    public static function setRunLog($jobid, $message)
    {
        $date = date("Y-m-d H:i:s");
        $sql = "insert into croner_run_log (jobid, cas, message) values ('$jobid', '$date', '$message')";
        framework_Database::getInstance("****")->insert($sql);
    }

    /**
     * sets first run of job log
     * @param int $jobid
     * @param int $pid
     * 
     * @return $id
     */
    public static function setJobLogStart($jobid, $pid)
    {
        $start = date("Y-m-d H:i:s");
        $sql = "insert into croner_log (job_id, start_run, pid) values ('$jobid', '$start', '$pid')";
        $id = framework_Database::getInstance("****")->insert_db($sql);
        return $id;
    }

    /**
     * finalize log for specified run
     * @param int $logid
     */
    public static function setJobLogEnd($pid, $endRunTime, $message)
    {
        $endRunTime = date("Y-m-d H:i:s", $endRunTime);
        $message = mysql_real_escape_string($message);
        $sql = "update croner_log set end_run = '$endRunTime', output = '$message' where pid = '$pid' and end_run is null";
        framework_Database::getInstance("****")->update($sql);
    } 
}

执行脚本:

$sql = "select id, runtime, execute_path from croner where runtime is not null and execute_path is not null";
//I am using database wrapper
$ret = framework_Database::getInstance("****")->select($sql);

$cj = new Cron_Job();

//echo date('d.m.Y.N.W H:i:s');
echo "<br>";
if(count($ret['id']) > 0)
{
    foreach($ret['id'] as $key=>$id)
    {
        $runtime = $ret['runtime'][$key];
        if(empty($runtime)) 
            continue;
        $cmd = $ret['execute_path'][$key];
        $outputfile = "/var/www-intranet/croner/outputs/" . $id . "_" . time();
        //echo $runtime;
        //if pregmatch than get details
        if(preg_match($runtime, date('d.m.Y.N.W H:i'), $matches))
        {
            Cron_Log::setRunLog($id, "Starting job $cmd");
            $cmd = sprintf("%s > %s 2>&1 & echo $!", $cmd, $outputfile);
            exec($cmd, $pid);
            $pid = $pid[0];
            //add log that job has started
            $cj->addRunningJob($pid, $outputfile);
            Cron_Log::setJobLogStart($id, $pid);
            usleep(2000);
        }
        else {
            continue;
        }   
    }
}


sleep(1);

//check running pids
$sql = "SELECT * FROM croner_running_pids";
$ret = framework_Database::getInstance("****")->select($sql);
//print_r($ret);
if(isset($ret['pid']) && count($ret['pid']))
{
    foreach($ret['pid'] as $key=>$pid)
    {
        if(is_numeric($pid) && !$cj->isJobRunning($pid) && file_exists($ret['outfile'][$key]))
        { //delete pid from run table
            $cj->deleteRunningJob($pid);
            $outfile = $ret['outfile'][$key];

            $endRunTime = filemtime($outfile);
            //echo $endRunTime;
            $message = file_get_contents($outfile);
            Cron_Log::setJobLogEnd($pid, $endRunTime, $message);
            @unlink($outfile);
        }
    }
}

数据库表:

克罗纳表:

Field   Type    Null    Key Default Extra
id      int(11) NO  PRI NULL    auto_increment
jobname varchar(250)    NO      NULL     
descr   text    NO      NULL     
runtime varchar(150)    NO      NULL     
execute_path text   NO      NULL     
creator int(11) NO      NULL     
last_run_time   timestamp   NO      CURRENT_TIMESTAMP   on update CURRENT_TIMESTAMP

Croner_log 表:

Field   Type    Null    Key Default Extra
id  int(11) NO  PRI NULL    auto_increment
job_id  int(11) NO      NULL     
start_run   timestamp   YES     NULL     
end_run timestamp   YES     NULL     
pid int(11) NO      NULL     
output  longtext    NO      NULL     

croner_run_log 表:

Field   Type    Null    Key Default Extra
id  int(11) NO  PRI NULL    auto_increment
jobid   int(11) NO      NULL     
cas timestamp   NO      CURRENT_TIMESTAMP   on update CURRENT_TIMESTAMP
message varchar(255)    NO      NULL     

croner_running_pids 表:

Field   Type    Null    Key Default Extra
id  int(11) NO  PRI NULL    auto_increment
pid int(11) NO      NULL     
pidfile varchar(250)    NO      NULL     
outfile varchar(250)    NO      NULL     

想法是,在数据库中进行配置,其中我以特定格式(date('d.m.Y.N.W H:i:s'))存储了 preg_match 的模式。此脚本计划每分钟运行一次。

然后,我总是选择所有模式并将它们与日期函数的结果进行匹配。

如果找到匹配项,我将运行为该作业存储的命令 - 将其置于后台并将其 pid 存储到数据库中 - 存储作业的所有输出的单独表。

最后,我在数据库中检查标记为正在运行的作业,并查看它们是否仍在进程列表中。

【讨论】:

    【解决方案2】:

    要获取 PHP 进程列表,请参阅以下问题:

    How to get list of running php scripts using PHP exec()?

    另一个选项是您可以获取文件的锁,然后在运行前检查它: 例如:

    $thisfilepath = $_SERVER['SCRIPT_FILENAME'];
    $thisfilepath = fopen($thisfilepath,'r');
    if (!flock($thisfilepath,LOCK_EX | LOCK_NB))
    {
      customlogfunctionandemail("File is Locked");
      exit();
    }
    elseif(flock($thisfilepath,LOCK_EX | LOCK_NB)) // Acquire Lock
    {
      // Write your code
    
    
     // Unlock before finish
     flock($thisfilepath,LOCK_UN);  // Unlock the file and Exit
     customlogfunctionandemail("Process completed. File is unlocked");
     exit();
    }
    

    基本上在上面的例子中,你首先检查文件是否被锁定,如果它没有被锁定(意味着进程完成)你可以获取锁定并开始你的代码。

    谢谢

    【讨论】:

    猜你喜欢
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 2012-12-02
    • 2017-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多