只要安裝了php 命令行工具就行
運行示例:
php supervisor.php /usr/local/nginx/bin/nginx nobody (這後面還可以加上對應命令的參數,無參數留空就行) &
參數介紹:第一個為命令行的php可執行程序,第二個為本文下面的代碼文件,第三個是需要啟動的可以執行的程序路徑,第四個是用什麼角色啟動它,後面的是預留參數,全部傳遞給這個可執行程序。
優點:
1、 需要守護的程序在 非daemon 狀態下運行,出現錯誤退出時能立即重啟
2、程序為daemon運行時,定時檢測運行狀態,1秒內重啟
3、能夠在特定的時間內設置重啟的次數,次數超過配置數就不再重啟,防止應用程序出現特別情況無法重啟。
建議:
建議把程序調成非daemon狀態下運行。
把以下代碼復制另存為supervisor.php文件即可
[php]
<?php
//author email: [email protected]
$_retry_times=5;
$_retry_times_duration=60;//這個是多少時間內,重啟了多少次,就不需要再重啟了
$_times_arr=array();
$args=$_SERVER['argv'];
if(count($args)<3)
{
write_log("args num error!");
write_log("etc: php supervisor.php /usr/local/nginx/bin/nginx nobody xxx");
write_log("第一個參數就是本文件,第二個參數是要監控的可執行文件路徑,第三個是使用哪個用戶執行,接下來的參數就是執行該執行文件所用的參數");
exit();
}
//$args[0] 為本文件名
$path=$args[1];
$username=$args[2];
for($i=3;$i>0;$i--)
array_shift($args);
while(1){
$pid=pcntl_fork();
if($pid==0)
{
//write_log("child ".getmypid()." run");
pcntl_exec($path,$args,$_SERVER);
write_log("execute file failed");
exit(0);
}
else if($pid>0)
{
//write_log(" main pid:".getmypid().", child_pid:".$pid);
$endpid=pcntl_waitpid($pid,$status,2);
//write_log("status:".$status);
if($status==0)
{
//說明可能是daemon程序,後台運行
if(file_exists("/proc/".($pid+1)."/stat"))
{
//說明進程存在,需要定時判斷
write_log("program start success");
for (;;)
{
if(file_exists("/proc/".($pid+1)."/stat"))
{
//write_log("program is alive");
usleep(1000000);
}
else
{
write_log("program die");
break;
}
}
}
else
{
//說明進程不存在,並且不是非daemon狀態。
write_log("program start failed");
exit(0);
}
}
else if($status>0)
{
//說明是非daemon 程序,退出來了,需要重新啟動
write_log("program die");
//continue;
}
else
{
exit(0);
}
if(chk_need_start($_times_arr,$_retry_times_duration,$_retry_times))
{
continue;
}
else
{
break;
}
}
};
function write_log($msg)
{
print(date('Y-m-d H:i:s').' '.$msg."\n");
}
function chk_need_start(&$_times_arr,$_retry_times_duration,$_retry_times)
{
foreach($_times_arr as $k=>$v)
{
//write_log("duration:".$_retry_times_duration);
if($k<time()-$_retry_times_duration)
{
//write_log("do unset");
unset($_times_arr[$k]);
}
}
//write_log("buffer count:".count($_times_arr));
if(count($_times_arr)>=$_retry_times)
{
return false;
}
else
{
$_times_arr[time()]=1;
return true;
}
}
?>
<?php
//author email: [email protected]
$_retry_times=5;
$_retry_times_duration=60;//這個是多少時間內,重啟了多少次,就不需要再重啟了
$_times_arr=array();
$args=$_SERVER['argv'];
if(count($args)<3)
{
write_log("args num error!");
write_log("etc: php supervisor.php /usr/local/nginx/bin/nginx nobody xxx");
write_log("第一個參數就是本文件,第二個參數是要監控的可執行文件路徑,第三個是使用哪個用戶執行,接下來的參數就是執行該執行文件所用的參數");
exit();
}
//$args[0] 為本文件名
$path=$args[1];
$username=$args[2];
for($i=3;$i>0;$i--)
array_shift($args);
while(1){
$pid=pcntl_fork();
if($pid==0)
{
//write_log("child ".getmypid()." run");
pcntl_exec($path,$args,$_SERVER);
write_log("execute file failed");
exit(0);
}
else if($pid>0)
{
//write_log(" main pid:".getmypid().", child_pid:".$pid);
$endpid=pcntl_waitpid($pid,$status,2);
//write_log("status:".$status);
if($status==0)
{
//說明可能是daemon程序,後台運行
if(file_exists("/proc/".($pid+1)."/stat"))
{
//說明進程存在,需要定時判斷
write_log("program start success");
for (;;)
{
if(file_exists("/proc/".($pid+1)."/stat"))
{
//write_log("program is alive");
usleep(1000000);
}
else
{
write_log("program die");
break;
}
}
}
else
{
//說明進程不存在,並且不是非daemon狀態。
write_log("program start failed");
exit(0);
}
}
else if($status>0)
{
//說明是非daemon 程序,退出來了,需要重新啟動
write_log("program die");
//continue;
}
else
{
exit(0);
}
if(chk_need_start($_times_arr,$_retry_times_duration,$_retry_times))
{
continue;
}
else
{
break;
}
}
};
function write_log($msg)
{
print(date('Y-m-d H:i:s').' '.$msg."\n");
}
function chk_need_start(&$_times_arr,$_retry_times_duration,$_retry_times)
{
foreach($_times_arr as $k=>$v)
{
//write_log("duration:".$_retry_times_duration);
if($k<time()-$_retry_times_duration)
{
//write_log("do unset");
unset($_times_arr[$k]);
}
}
//write_log("buffer count:".count($_times_arr));
if(count($_times_arr)>=$_retry_times)
{
return false;
}
else
{
$_times_arr[time()]=1;
return true;
}
}
?>