【问题标题】:Running a PHP process as a daemon while safely killing it from background将 PHP 进程作为守护进程运行,同时从后台安全地杀死它
【发布时间】:2023-03-11 08:39:01
【问题描述】:

我们正在运行一个 PHP 守护程序,它查看队列,接收工作人员作业并生成工作人员来处理它。工人自己在继续之前获得对特定位置的锁定。

我们将守护进程生成为 nohup 后台进程。

整个架构似乎都可以工作,除非我们必须终止进程,无论出于何种原因。如果我们使用 -9 杀死它们,则无法将其捕获在工作进程中并在死前释放锁。

如果我们使用小于 -9 的任何内容(如 TERM 或 HUP),守护进程或工作进程似乎都不会收到它。

有人用更好的方法解决了这个问题吗?

(ps:顺便说一句,由于其他考虑,我们可能无法更改我们的实现语言,所以请只考虑基于PHP的解决方案)

【问题讨论】:

  • 是PHP5.3(或以上)吗?如果是,您是否在守护程序代码之上使用了pcntl_signal_dispatch(); 或以其他方式声明了ticks?主守护进程是否阻塞等待子进程?孩子们有没有阻塞 IO?
  • SIGKILL 有点野蛮;当您在前台运行 SIGTERM 时它会起作用吗?
  • 声明滴答似乎已经成功了。不幸的是 pcntl_signal 的文档并没有以更引人注目的方式提及它。声明后,它已开始按预期工作。
  • @hek2mgl 随意输入答案,我会接受,或者我会等到明天自己输入答案..
  • @Shreeni 好的,会回答的! :)

标签: php kill-process daemons


【解决方案1】:

我也遇到过相关问题。让我解释。我有一个像下载器一样工作的 php '守护进程'。它定期访问提要并从网络下载(laaaarge)内容。守护进程必须在某个时间停止,比如说早上 0500,以防止它在白天使用整个带宽。我决定使用 cronjob 将 SIGTERM 发送到 0500 的守护进程。

在守护进程中我有以下代码:

pcntl_signal(SIGTERM, array($this, 'signal_handler'));

signal_handler 看起来像这样:

public function signal_handler($signal) {
    // some cleanup code 
    exit(1);
}

不幸的是,这不起作用:|

我花了一段时间才弄清楚发生了什么。我首先想到的是,我必须在 init 上调用方法 pcntl_signal_dispatch() 才能完全启用信号调度。引用文档 (comments):

如果您将 PHP 作为 CLI 和“守护程序”(即在循环中)运行,则必须在每个循环中调用此函数以检查是否有新信号正在等待分派。

好的,到目前为止,它似乎有效。但我很快意识到,在某些条件下,即使这样也不会按预期工作。有时守护进程只能被kill -9 停止 - 和以前一样。 :|

那么问题出在哪里?.. 答:我的程序名为wget,通过shell_exec 下载文件。问题是,shell_exec() 阻塞等待子进程终止。在此阻塞等待期间,未完成任何信号处理,只能使用 SIGKILL 终止该进程——这很难。还有一个问题是,子进程在杀死父进程后变成僵尸进程,必须一个一个地终止。

对此我的解决方案是使用proc_open() 执行子进程,并在其输出上使用stream_select() 以实现非阻塞IO。

现在它就像一个魅力。 :) 如果您需要更多信息,请随时发表评论。


注意如果您使用的是 PHP

declare(ticks=1);

而不是pcntl_signal_dispatch()。你可以参考pcntl_signal() 的文档。但如果可能的话,你应该升级到 PHP >= 5.3

【讨论】:

  • 我的问题只是通过声明刻度来解决:declare(ticks = 1);
  • @Shreeni 这是因为 pcntl_signal_dispatch() 从 PHP 5.3 开始工作,declare(ticks=1) 是 PHP
【解决方案2】:

这个问题通过添加刻度就解决了:

// tick use required as of PHP 4.3.0
declare(ticks = 1);

不理会这会导致我的代码无法工作。

*(很遗憾,pcntl_signal 的文档并没有以更引人注目的方式提及它。)*

【讨论】:

    【解决方案3】:

    您需要捕捉信号 (SIGTERM)。这可以通过函数pcntl_signal 来实现。这将使您可以选择在调用 exit 之前执行任何必要的功能。

    【讨论】:

    • 如问题中所述,尽管通过 pcntl_signal 设置了处理程序,但似乎 SIGTERM 没有被捕获。
    猜你喜欢
    • 2023-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 2016-11-12
    相关资源
    最近更新 更多