How to get list of PHP processes running on server with PHP

前端 未结 2 564
后悔当初
后悔当初 2021-01-06 08:44

I have a cronjob that runs a PHP file that runs a DAEMON written in PHP, but I only want to run the DAEMON if no other instances of it are running, how can I get a list of P

相关标签:
2条回答
  • 2021-01-06 08:54

    To get the list of PHP processes see this question:

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

    Another option is that you can acquire a lock of the file and then check it before running: for example:

    $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();
    }
    

    Basically in the above example you are first checking if the file is locked or not and if it is not locked (means process is completed) you can acquire lock and begin your code.

    Thanks

    0 讨论(0)
  • 2021-01-06 09:15

    Here is my full solution to take control over cron with php script which envolves mysql db for configuration and logging. You should find answers to your questions in source code.

    Cron_Job class:

    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);
        }
    }
    

    class 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);
        } 
    }
    

    executing script:

    $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);
            }
        }
    }
    

    DB tables:

    Croner table:

    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 table:

    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 table:

    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 table:

    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     
    

    The idea is, to have configuration in database, where I have stored patterns for preg_match in specific format (date('d.m.Y.N.W H:i:s')). This script is schleduled to run every minute.

    Then, I am always selecting all patterns and matching them against result from date function.

    If match is found, I will run command stored for that job - put it in background and store its pid into database - separate table where all outputs from jobs are stored.

    At the end, I am checking in database for jobs that are marked as running and looking if they are still in process list.

    0 讨论(0)
提交回复
热议问题