簡體   English   中英

PHP 阻止 SIGTERM 冒泡到 proc_open 進程

[英]PHP prevent SIGTERM to bubble to proc_open process

原始問題(在 CTRL+C 上將 SIGTERM 發送給孩子,父母應該等待它關閉)。 請參閱下面的更新!

我有一個 PHP 腳本(見下文)啟動一個進程並跟蹤它的輸出。 這個過程一直運行,直到我通過按 CTRL+C 或向 PHP 腳本 (pid) 發送 SIGTERM 信號來要求 PHP 停止。 此時 PHP 決定立即終止由 proc_open 啟動的進程,而不是優雅地關閉它並在關閉之前等待它,我該如何實現呢?

我嘗試了一些事情,比如添加pcntl_waitpid($childPid)等,但到目前為止顯然沒有運氣。

<?php

// Handle close signals (like CTRL+C).
function closeChildApplication(int $signal) {
    // ???
}

// Async signals instead of declare(TICKS=1) PHP 7.1+
pcntl_async_signals(true);
pcntl_signal(SIGTERM, 'closeChildApplication', false);
pcntl_signal(SIGINT, 'closeChildApplication', false);

// Create process.
$descriptors = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe', 'w']
];
$proc = proc_open('<command-to-run>', $descriptors, $pipes);
if (!is_resource($proc)) {
    throw new \RuntimeException('Could not execute <command-to-run>.');
}

// Not sending any data to child, so close STDIN immediately.
fclose($pipes[0]);

// Non blocking mode.
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);

do {
    $status = proc_get_status($proc);

    $data = '';
    while (!feof($pipes[1]) && false !== ($line = fgets($pipes[1]))) {
        $data .= $line;
    }
    if (!empty(trim($data))) {
        // STDOUT logic here.
    }

    $data = '';
    while (!feof($pipes[2]) && false !== ($line = fgets($pipes[2]))) {
        $data .= $line;
    }
    if (!empty(trim($data))) {
        // STDERR logic here.
    }

    sleep(1);
} while ($status['running']);

// Not running anymore, close resource.
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($proc);

更新似乎 PHP正在等待孩子被關閉,但有問題的程序沒有很好地處理 SIGTERM 和 SIGINT 並立即殺死自己而不是清理和關閉。 我發現我可以將 QUIT 命令發送到程序 STDIN 以觸發干凈關閉。

但是我現在面臨的問題是,當 PHP 接收到 SIGTERM/SIGINT 信號時,這也會發送到使用 proc_open 打開的程序(因此它會冒泡到孩子身上)。

如果發現我們可以玩一下,我們可以做pcntl_signal(SIGTERM, SIG_IGN, false); 這會導致 PHP 忽略該信號並阻止它被發送給孩子。 但現在我不知道是否發送了信號。

另一種方法是:

function closeChildApplication(int $signal) {
    // do nothing in here.
}

pcntl_signal(SIGTERM, 'closeChildApplication', false);

在這種情況下,PHP 會忽略信號並繼續運行,但子進程會收到信號並被殺死。 任何知道如何防止信號冒泡給孩子或忽略信號但例如在下面檢查是否收到任何信號的人?

因此,經過幾天對這個問題的困惑后,如果發現 proc_open 似乎有點繼承 PHP 關於 SIG_IGN 信號的設置。

當說pcntl_signal(SIGTERM, SIG_IGN, false); PHP 和 proc_open 打開的進程都忽略這個信號。

當說pcntl_signal(SIGTERM, function(){ echo 'test'; }, false); PHP 回顯“測試”並繼續運行,但是 proc_open 打開的進程也收到 SIGTERM 並自行關閉。

但有趣的是,當我這樣做時:

// Ignore all signals:
pcntl_signal(SIGTERM, SIG_IGN, false);

// Start program:
proc_open('command // etc');

// Install signal handler for PHP:
pcntl_signal(SIGTERM, function(){ echo 'test'; }, false);

PHP 在接收信號時回顯“測試”,但以 proc_open 開始的進程沒有對 SIGTERM 信號做任何事情,這向我表明 SIG_IGN 是由 proc_open 繼承的。

這正是我現在需要的,但有點奇怪,這是告訴 proc_open 忽略某些信號的唯一方法,不確定這是預期行為還是 PHP 錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM