php - 无法在某些子进程成为僵尸之前终止它们
问题描述
环境:Debian Buster,php 7.4
几天前我写了一个新的任务管理器,我遇到了终止子进程的问题。我阅读了以下页面以获取信息:
- 终止从套接字服务器派生的僵尸子进程
- https://www.php.net/manual/en/function.pcntl-fork.php
- https://www.php.net/manual/en/function.pcntl-wait.php
- https://unix.stackexchange.com/questions/105998/why-process-program-becomes-zombie
还有一堆其他的,但这些是最重要的。
所以我的问题是,在我的任务管理器中,我有一个信号接收器功能,理论上应该从内存中清除 PID,但它并不总是发生。它没有发生的方式就像父进程开始忽略这些信号,从那时起,一切都不再重要,每个子进程都将成为僵尸进程。
所以简化的主流程看起来像这样:
public function childCaretaker(int $signo): void
{
$this->info("Received PCNTL signal {$signo}");
$pid = pcntl_wait($status);
// actually this part below doesn't matter
if ($pid !== 0 && posix_kill($pid, 9)) {
$this->info("Child {$pid} has tragically died!");
unset($this->processes[$pid]);
}
}
public function actionRunWorker(bool $priorityLevel = false)
{
set_time_limit(0);
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, [$this, 'childCaretaker']);
// not important code here
while (1) {
// Processes tasks in individual processes if there is any available in the database
$taskCount = $this->queue->processTasks($this->processes, $priorityLevel);
// not important code here
}
}
然后在实际处理块中,我检查是否有足够的内存来从最大可用减去安全区域创建新进程。如果有,那么我查询最多 100 个任务,然后使用 foreach 创建新进程 - 如果有足够的内存,再次创建新进程 - 并为其创建新的数据库连接并在退出前关闭它。
public function processTasks(array &$processes, $priorityLevel = false): int
{
// not important code
/** @var BaseTask $task */
foreach ($executableTasks as $task) {
// not important code
$pid = pcntl_fork();
// not important code
switch ($pid) {
case -1:
Yii::error('Could not fork!', 'tasks');
exit(0);
case 0:
// not important code
try {
// Process the task
$task = $this->process($priorityLevel);
} catch (\Exception $exception) {
// not important code
exit(0);
}
$executionTime = microtime(true) - $taskExecutionStarted;
// not important code
exit(0);
default:
$processes[$pid] = true;
break;
}
}
// not important code
}
那么我实际上能做些什么来摆脱僵尸一代呢?在上面的一个链接中,有人解释说它不可能杀死僵尸进程 - 因为它的设计是我在 cli 中手动尝试的,这也有点令人困惑,因为在其他一些来源上,人们提到 SIGKILL 应该总是工作(这不是真的)。
解决方案
推荐阅读
- php - 使用 PHP 上传大文件
- kurento - Hello World(环回中的 WebRTC)远程视频流在 Ubuntu 16.04.6 LTS 中不起作用
- scala - Scala 中的柯里化函数
- javascript - 我有 6 个对象属性,称为 item1、item2 到 item6,它们不在我可以循环的数组中。如何干燥我的代码?
- java - Firebase 图像存储 - 从 Firebase 实时数据库 + 存储中加载原始图像之前的缩略图
- java - Apache Storm 和 Kafka 与 Firebase 的集成
- go - 从 exec.Command 写入文件
- postgresql - postgreSQL : oracle sqlerrm 相当于 postgres
- yii - yii1.1出现“CDbCommand failed to execute the SQL statement FOREIGN KEY”错误信息如何处理
- c# - 根据标准比较两个对象