【PHP実践|実務向け】PHPでシグナルをスマートに制御する:EvSignalクラスの活用術

導入

バックエンドエンジニアとして、デーモンプロセスや長時間稼働するCLIツールを開発する際、SIGINT(Ctrl+C)やSIGTERMによる安全な停止処理(グレースフルシャットダウン)の実装は避けて通れません。PHPの標準的なpcntl_signal()は、シグナルの発生タイミングが非同期であるため、処理の途中で割り込まれるリスクがあります。ここで紹介する「EvSignalクラス」は、libevライブラリを用いたイベントループの一部としてシグナルを処理するため、同期的にかつ安全にシグナルを受け取ることができます。

基礎知識

EvSignalは、PECLの「ev」拡張モジュールに含まれるクラスです。イベント駆動プログラミングにおいて、シグナルを「イベント(監視対象)」として登録します。
主な特徴:
・シグナルをイベントループの一部として処理するため、メインのプログラムフローと同期が取れる。
・同一シグナルを複数のループで同時に監視することはできない(SIGCHLDはデフォルトループに固定される)。
・libevが可能な限りシステムコールを中断させないよう制御してくれる。

実装/解決策

EvSignalを使用するには、まずイベントループ(EvLoop)を作成し、そのループに対してEvSignalを登録します。コンストラクタには「監視するシグナル番号」と「発生時のコールバック関数」を渡します。登録後は、loop()メソッドを呼び出すことで監視が開始されます。

サンプルプログラム

以下のコードは、CLI実行中にCtrl+Cが押された際に、安全にシャットダウン処理を実行する例です。

stop();
Ev::stop();
});

echo “プロセスの監視を開始しました(Ctrl+Cで停止)\n”;

// イベントループを開始(シグナルを待機)
$loop->run();

echo “正常に終了しました。\n”;
?>

応用・注意点

1. システムコールの割り込み回避
もし処理中のシステムコールがシグナルによって中断され、エラーになる場合は、EvCheckやEvPrepareウォッチャーを使用してシグナルを一時的にブロック・アンブロックするテクニックが有効です。

2. pcntl拡張との併用
EvSignalを使う際、シグナル番号の指定にはpcntl拡張で定義されている定数(SIGINT, SIGTERMなど)を利用します。そのため、php-pcntlがインストールされていることが前提となります。

3. デバッグのコツ
EvSignalは非同期処理の一種であるため、エラー発生時にスタックトレースが追いにくい場合があります。重要な処理はtry-catchで囲み、ログ出力によるデバッグを徹底してください。また、長時間稼働させるプロセスであれば、メモリリークを避けるため、コールバック内でのオブジェクトの保持には十分注意しましょう。

タイトルとURLをコピーしました