在自己设计的消息队列里,主要是一个while循环,通过while循环里不断去读取Redis队列里的参数,
来达到消息队列的目的。可是,有可能进程会被突然杀掉,或者被人为的kill掉,如果被强行kill掉后,
会导致while里的部分逻辑走不完,走不完会导致部分数据的丢失。
<?php
class ModTest {
private $cnt = 0;
// 构造函数,用来处理基本信息
public function __construct() {
pcntl_signal(SIGHUP, array($this, 'sigHandler'));
pcntl_signal(SIGINT, array($this, 'sigHandler'));
pcntl_signal(SIGQUIT, array($this, 'sigHandler'));
pcntl_signal(SIGILL, array($this, 'sigHandler'));
pcntl_signal(SIGFPE, array($this, 'sigHandler'));
pcntl_signal(SIGALRM, array($this, 'sigHandler'));
pcntl_signal(SIGTSTP, array($this, 'sigHandler'));
pcntl_signal(SIGABRT, array($this, 'sigHandler'));
pcntl_signal(SIGTERM, array($this, 'sigHandler'));
// shutdown
register_shutdown_function(array($this, 'shutdownHandler'));
}
public function startPush() {
while (true) {
PubFileLog::writeDebugInfo('before, cur num is : ' . $this->cnt);
pcntl_signal_dispatch();
$this->cnt++;
PubFileLog::writeDebugInfo('after, cur num is : ' . $this->cnt);
sleep(15);
PubFileLog::writeDebugInfo('ssssssss');
}
}
/**
* 异常退出处理函数
*/
public function shutdownHandler() {
$data = error_get_last();
PubFileLog::log(json_encode($data), '/tmp/***.log');
}
/**
* 信号处理函数
* @param int $signal
*/
public function sigHandler($signal) {
$data = array(
'sig_no' => $signal,
);
PubFileLog::log(json_encode($data), '/tmp/***.log');
switch ($signal) {
case SIGHUP:
case SIGINT:
case SIGQUIT:
case SIGILL:
case SIGFPE:
case SIGALRM:
case SIGTSTP:
case SIGABRT:
break;
case SIGTERM:
// SIGTERM信号时,退出进程
exit();
break;
default:
break;
}
}
}
参考上面的代码,当我们执行startPush后,除非人为的把进程kill掉或者其他因素,那么这个循环就会一直执行下去。
我们可以在进程退出的时候,进行监测,除了SIGTERM($signal=15),其他情况下都是break。
而且当系统监测到是kill -15时,会等到执行完pcntl_signal_dispatch()这个函数才会正式退出(走到代码的sigHandler函数里)。