控制台脚本从外部API执行数据导入。用于增强由pcntl_fork
命令创建的并发进程中执行的导入加载。
对于与API的通信,使用cUrl。通过https协议执行的通信。
由于一些不明确的原因,一些孩子会定期成为僵尸。控制台中没有错误/警告/通知,也没有写入日志。错误级别已正确配置。
经过调查我认为卷曲扩展存在问题,因为没有它,假连接,没有问题。 此外,如果在单一过程模式下运行导入 - 根本没有问题。
PHP:7.2.4, 操作系统:Debian 9, 卷曲:7.59.0(x86_64-pc-linux-gnu)libcurl / 7.47.0 OpenSSL / 1.0.2g zlib / 1.2.8 libidn / 1.32 librtmp / 2.3
也许有人遇到类似问题或者知道这种奇怪行为的可能原因?
儿童逻辑的伪代码样本(儿童的主要部分表示):
while (true) {
$socket->writeRawString(Signal::MESSAGE_REQUEST_DATA);
$response = $socket->readRawString();
if (Signal::MESSAGE_TERMINATE_PROCESS === $response) {
break;
}
$response = json_decode($response, true);
if (empty($response) || empty($response['deltaId'])) {
continue;
}
$delta = $this->providerConnection->getChanges($response['deltaId']);
if(empty($delta)) {
continue;
}
$xmlReader = new \XMLReader();
$xmlReader->XML($delta);
$xmlReader->read();
$xmlReader->read();
$hasNext = true;
while ($hasNext && 'updated' !== $xmlReader->name) {
$hasNext = $xmlReader->next();
}
if ('updated' !== $xmlReader->name) {
throw new \RuntimeException('Deltas file do not contain updated date.');
}
if (strtotime($xmlReader->readString()) < $endDateTimestamp) {
$socket->writeRawString(self::SIGNAL_END_DATE_REACHED);
continue;
}
}
posix_kill(\posix_getpid(), SIGTERM);
在通过cUrl执行的providerConnection->getChanges($response['deltaId']);
请求中。对于使用Php cUrl class扩展名
答案 0 :(得分:0)
正如我的评论中所提到的,你的问题可能是,父进程需要收集死亡/完成的子进程,否则它们仍然是僵尸。
第一个解决方案:
在父级中安装信号处理程序。像这样:
pcntl_signal(SIGCHLD, [$this, 'handleSignals']);
使用可能如下所示的信号处理程序:
/**
* @param integer $signal
*/
public function handleSignals($signal) {
switch($signal) {
case SIGCHLD:
do {
$pid = pcntl_wait($status, WNOHANG);
} while($pid > 0);
break;
default:
//Nothing to do
}
}
我通常会存储分叉儿童的pids并使用pcntl_waitpid
单独检查它们,但这可以帮助你。
第二个解决方案:
如果父级不需要等待所有子任务完成,则使用双叉来生成子进程。双叉看起来像这样:
$pid = pcntl_fork();
if ($pid == -1) handleError();
elseif ($pid == 0) { // child
$pid = pcntl_fork();
if ($pid == -1) handleChildError();
elseif($pid == 0) { // second level child
exit(startWork()); // init will take over this process
}
// exit first level child
exit(0);
} else {
// parent, wait for first level child
pcntl_wait($pid, $status); // forked child returns almost immediatly, so blocking wait is in order
}
答案 1 :(得分:0)
我放弃使用cUrl完成我的任务。今天我用StreamHandler而不是cUrl切换到Guzzle,它解决了我所有的问题。
我想,由于cUrl中的一些内部错误,系统正在杀死我的子进程。
这不是我的问题的答案。对于那些可能遇到类似问题的人来说,这只是我的问题的解决方法。
主题仍然可以提供可能的建议/解释。