-->

2010-10-11

pcntl_fork の例

子プロセスを作成する例です。
myDaemon.2010-10-11.tar.gz をダウンロードします。
設定の変更と子プロセスの内容の変更は myDaemon.php です。
起動方法の例です。
$ php myDaemon.php
$ tail -f /tmp/myDaemon.child_log
...
$ kill -TERM `cat /tmp/myDaemon.pid` # 止まる。
$ kill -USR1 `cat /tmp/myDaemon.pid` # 子プロセスの終了を待って止まる。
$ kill -HUP -`cat /tmp/myDaemon.pid` # ログファイルを再度開く。子プロセスも開く。

説明です。
<?php

// シグナルを受け取るのに必要です。
declare(ticks = 1);

// クラスをロードします。
require_once("class.myDaemonBase.php");

// クラスの設定を変更します。
class myDaemon extends myDaemonBase
{
    // 親プロセスのPIDの保存先
    protected $pidFile         = "/tmp/myDaemon.pid";
    // 親プロセスのログの保存先
    protected $mainLogFile     = "/tmp/myDaemon.log";
    // 子プロセスのログの保存先
    protected $childLogFile    = "/tmp/myDaemon.child_log";
    // phpエラーをフックする前に出るphpエラーの保存先
    protected $phpErrorLogFile = "/tmp/myDaemon.php_error_log";
    // 子プロセスの数
    protected $maxChildNum     = 10;
    // 無限にループする部分で1回ごとに休憩する秒数
    protected $sleepTime       = 1;
    // ログを増やすかどうか?
    protected $debugFlag       = false;
}

// 子プロセスが実行する関数名
function childProcess($class)
{
    $class->Logger("Start child process");
    $time = rand(1, 60);
    $class->Logger("Sleep for {$time} seconds.");
    for ($i = 0; $i < $time; $i++)
    {
        sleep(1);
    }
    $class->Logger("End child process");
}

// 常駐プロセスの起動
myDaemon::start();
exit(0);

メモリの設定が足りていないと子プロセスの生成と終了を繰り返す例です。
$ cat /etc/php/cli-php5/php.ini | grep -v ^\; | grep -v ^$ > myDaemon.ini
$ emacs myDaemon.ini
$ cat myDaemon.ini
short_open_tag                 = Off
allow_call_time_pass_reference = Off
memory_limit                   = 8M
error_reporting                = E_ALL
display_errors                 = STDERR
log_errors                     = On
error_log                      = /tmp/myDaemon.php_error_log
log_errors_max_len             = 4096
register_long_arrays           = Off
include_path                   = ".:/usr/share/php5:/usr/share/php"
enable_dl                      = Off
allow_url_fopen                = Off

extension = pcntl.so
extension = mbstring.so

mbstring.language             = Japanese
mbstring.internal_encoding    = UTF8
mbstring.http_input           = auto
mbstring.http_output          = pass
mbstring.encoding_translation = On
mbstring.detect_order         = auto
mbstring.substitute_character = 0x3013
mbstring.func_overload        = 0
$ php -n -c myDaemon.ini myDaemon.php
$ sleep 3
$ kill `cat /tmp/myDaemon.pid`
$ tail -n1 /tmp/myDaemon.php_error_log
[17-Oct-2010 01:51:37] PHP Fatal error:  Allowed memory size of 8388608 bytes exhausted (tried to allocate 10485761 bytes) in /var/www/localhost/php/System_Daemon/myDaemon.php on line 26
狙いは動的にロードするモジュールを最低限にすること、
設定の変更を、変更したい部分だけに絞ってわかりやすくすること、です。

例えば、変更したことによってプログラムが memory_limit=8M 以上ないと動かない、
などのハードウェィアへの依存度がわかったり、
phpのバグだと認識していたものが、ただの設定の違いであることが判明したり、
するかもしれません。

よって例えば centos5 の php5.1.6 のデフォルトがあなたの利用する全てのphpである場合、
このような設定の変更は、混乱するだけです。

php -n は /etc/php.ini などを全て読みません。
php -c ファイル名は、設定ファイルを追加で読みます。
php5.2より新しくないと -n と -c は同時に使えないかもしれません。

error_reporting = E_ALL はお勧めです。
バグが必ずあるとして E_NOTICE を発生させるタイプは、すぐに対応できる、というのが主な理由です。
E_NOTICE が邪魔というのは、すぐになれる可能性が高いです。(正常な場合に出ないように書くのは容易という意味です。)
対して E_NOTICE が発生するミスというのはログに取れないと特定が大変です。
デフォルトが E_ALL & ~E_NOTICE であると仮定した場合の話です。
例えば perl で use strict; use warnings; があった場合に少し安心しますが、それに似ています。
log_errors=On, error_log=filename, display_errors=0|1|stderr もセットで有効です。

0 件のコメント: