下面是一个例子的代码PHP worker
。网络上的所有示例都使用 proc_open() 并打开子进程来完成工作。
Worker.php 与子进程
ini_set('display_errors', 'On');
ini_set('error_reporting', E_ALL);
error_reporting(E_ALL | E_NOTICE | E_STRICT);
function executeWorker($body) {
// open a php process and call the worker.php script
$pipes = array();
$process = proc_open(
'/usr/bin/php -d display_errors=stderr /var/www/project/worker.php',
array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w"),
3 => array("pipe", "r")
),
$pipes,
sys_get_temp_dir(),
null
);
var_dump($process);
if (is_resource($process)) {
// write the message into worker.php stdin
fwrite($pipes[0], $body);
fclose($pipes[0]);
// read errors from worker.php
$stdErr = stream_get_contents($pipes[2]);
fwrite($pipes[2], $stdErr);
fclose($pipes[2]);
$value = proc_close($process);
var_dump($value);
// if worker.php ends without errors, execution was successful
if ($value === 0 && empty($stdErr)) {
return true;
}
}
return false;
}
executeWorker('test');
但是使用 php register 错误处理程序,我们可以捕获 php worker 错误,然后我们可以将失败的作业写入数据库。
我的问题是如果我们使用 supervisord 为什么我们需要打开子进程?
例子
Worker.php 没有子进程
Class Worker
{
public $delay;
public $memory;
public $timeout;
public $sleep;
public $maxTries;
public function __construct()
{
static::registerExceptionHandler();
static::registerErrorHandler();
static::registerFatalErrorHandler();
}
public function init()
{
ini_set('error_reporting', 0); // Disable cli errors on console mode we already had error handlers.
ini_set('display_errors', 0);
// Don't change here we already cathc all errors except the notices.
error_reporting(E_NOTICE | E_STRICT); // This is just Enable "Strict Errors" otherwise we couldn't see them.
$this->memory = (int)$_SERVER['argv'][1]; // Sets maximum allowed memory for current job. Uses php ini_set('memory_limit', 'xM') function.
$this->delay = (int)$_SERVER['argv'][2]; // Sets job delay interval
$this->timeout = (int)$_SERVER['argv'][3]; // Sets time limit execution of the current job. Uses php set_time_limit() function..
$this->doJob();
}
public function doJob()
{
// do jobs in here ...
// $job->new JobClass();
// $job->release();
}
public static function registerErrorHandler($continueNativeHandler = false)
{
$previous = set_error_handler(
function ($level, $message, $file, $line) use ($errorPriorities, $continueNativeHandler) {
$iniLevel = error_reporting();
if ($iniLevel & $level) {
// echo $message; write process errors to database
}
return ! $continueNativeHandler;
}
);
}
public function registerExceptionHandler()
{
set_exception_handler(
function ($exception) {
$messages = array();
do {
$extra = array();
if (isset($exception->xdebug_message)) {
$extra['xdebug'] = $exception->xdebug_message;
}
$messages[] = array(
'priority' => $priority,
'message' => $exception->getMessage(),
'extra' => $extra,
);
$exception = $exception->getPrevious();
} while ($exception);
foreach (array_reverse($messages) as $message) {
// echo $message write failures to database
}
}
);
return true;
}
public static function registerFatalErrorHandler()
{
register_shutdown_function(
function () {
if (null != $error = error_get_last()) {
// Write fatal errors to
}
}
);
}
}
// END Worker class
使用主管
vi myMailer.conf
[program:myMailer]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/project/worker.php --memory:128 --delay=0 --timeout=3
numprocs=3
autostart=true
autorestart=true
stdout_logfile=/var/www/project/data/logs/myMailerProcess.log
stdout_logfile_maxbytes=1MB
启动所有工人
supervisorctl start all
myMailer_02: started
myMailer_01: started
myMailer_00: started
myImages_02: started
myImages_01: started
myImages_00: started
然后开始进程
主管
myMailer:myMailer_00 RUNNING pid 16847, uptime 0:01:41
myMailer:myMailer_01 RUNNING pid 16846, uptime 0:01:41
myMailer:myMailer_02 RUNNING pid 16845, uptime 0:01:41
那么为什么我们需要使用 proc_open() 函数呢?