我有一个运行PHP文件的cronjob,它运行用PHP编写的DAEMON,但我只想运行DAEMON,如果没有其他实例正在运行,我怎样才能获得运行的PHP进程列表找到我的DAEMON是否正在运行。我想到了某种类型的exec,它会生成一个我可以存储在数组中的列表。有任何想法吗?感谢
答案 0 :(得分:4)
要获取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();
}
基本上在上面的示例中,您首先检查文件是否已锁定,如果文件未锁定(表示处理已完成),您可以获取锁定并开始编码。
由于
答案 1 :(得分:0)
这是我用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);
}
}
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);
}
}
执行脚本:
$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);
}
}
}
数据库表:
Croner表:
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
我的想法是,在数据库中进行配置,我已经以特定格式存储了preg_match的模式( date('d.m.Y.N.W H:i:s'))。这个脚本每分钟运行一次。
然后,我总是选择所有模式并将它们与日期函数的结果进行匹配。
如果找到匹配,我将运行为该作业存储的命令 - 将其放入后台并将其pid存储到数据库中 - 单独的表中存储作业的所有输出。
最后,我正在数据库中检查标记为正在运行的作业,并查看它们是否仍处于进程列表中。