【发布时间】:2019-12-31 22:36:51
【问题描述】:
我有一个 Perl 应用程序,它在 RH 系统上运行了几年,基本上没有问题。在一个地方,我必须运行一个可能需要几分钟才能完成的系统命令,所以我在一个子进程中执行此操作。整体结构是这样的:
$SIG{CHLD} = 'IGNORE'; # Ignore dead children, to avoid zombie processes
my $child = fork();
if ($child) { # Parent; return OK
$self->status_ok();
} else { # Child; run system command
# do a bunch of data retrieval, etc.
my $output;
my @command = # generate system command here
use IPC::System::Simple 'capture';
eval { $output = capture(@command); };
$self->log->error("Error running @command: $@") if $@;
# success: log $output, carry on
}
我们最近改变了我们的一些基础设施,虽然没有以我预期的方式对此产生任何影响。 (仍在 RH 上运行,仍在使用 nginx 等)但是,现在我们发现运行此代码的几乎每个实例都失败了,记录 'Error running {command}: failed to start: "No child processes" at /path/to /code.pl'。
我环顾四周,不知道什么是正确的解决方案。有人建议将$SIG{CHLD} 从“IGNORE”更改为“DEFAULT”,但我不得不担心僵尸进程。
是什么导致了“无子进程”错误,我们如何解决这个问题?
【问题讨论】:
-
当父进程没有在子进程的退出代码上
wait时,你会得到僵尸进程。status_ok()是做什么的?这会退出程序吗?等孩子?您可能应该处理 SIG_CHLD; stackoverflow.com/questions/1608017/… 可能会有所帮助。 -
这是在一个web框架中;
status_ok()基本上是向前端发送一条消息,说“您的请求正在处理中;您应该很快收到包含完整详细信息的电子邮件”,然后退出(我们在孩子的系统命令完成时发送电子邮件)。我们不会在任何地方处理SIG_CHLD,我也不确定如何处理。但同样,这已经运行了多年,直到最近才出现问题。 -
评论应改为“忽略死去的孩子,确保他们变成僵尸”
-
如果父级通常在发送响应后退出,则子级将被 pid 1 继承并立即等待。如果你现在得到僵尸,那是因为父母没有退出。尝试发送响应时可能会阻塞。
-
我会添加一些监控代码。在父级中,使用
kill 0, $child和ps监视子级。在孩子中,在执行之前检查命令,例如ls -la $command[0]。解码 $?和美元!。尝试手动生成,而不是使用 IPC::System::Simple。尝试 IPC::Cmd。尝试手动运行 shell 提示符下包含的任何@command。尝试在命令前添加strace。无法启动的命令可能有奇怪的原因。也许你需要变基。也许一个新的库正在挂钩您的流程并破坏它。 HTH。