なんかデーモンっぽいものを作らないといけないなぁということになって、それまでCakePHPでシステムを作っていたので、やっぱりデーモンもPHPかということになって、作ってみたら意外と簡単でしたよという話。
まぁ、デーモンのようなものをPHPで作らなくても良いでしょうという意見もあると思うのですが、バッチリLAMP環境ができあがっている昨今、やっぱりPHPでやれちゃうというのは楽なんですよね。
PHPでデーモンを作るには、POSIXに対応したPHP環境と、System_DaemonというPEARライブラリが必要です。あと、System_Daemonからログを出すためにLogというPEARライブラリも。
CentOS+remiとかでyumインストールしたPHPは、—disable-posixというオプション付でコンパイルされているので、そのままの状態ではデーモンを作っても実行時にエラーとなってしまいます。
yum install php-posix
これで、POSIXが有効化されたPHPになります。
System_DaemonとLogのインストールは、
pear install System_Daemon-beta
pear install Log
System_Daemonは現時点では1.0.0RC1なので、-betaを付けてインストールする必要があります。
あとは、Web屋のネタ帳の常駐プロセス(デーモン)として動くアプリを自作する(PHPとPEAR:: System_Daemon編)を参考に。
<?php
require_once('Log.php');
require_once('System/Daemon.php');
$logger = &Log::singleton('file', 'hoge.log', 'hoge', null, PEAR_LOG_DEBUG);
$options = array( 'appName' => 'hogeDaemon',
'appDescription' => 'hoge daemon test',
'appDir' => dirname(__FILE__),
'sysMaxExecutionTime' => '0',
'sysMaxInputTime' => '0',
'usePEARLogInstance' => $logger,
'logVerbosity' => '7',
);
System_Daemon::setOptions($options);
System_Daemon::start();
//DB接続
System_Daemon::debug('DB接続したよ');
while (!System_Daemon::isDying()) {
System_Daemon::iterate(5);
//メイン処理
System_Daemon::debug('メイン処理中');
}
//DB切断
System_Daemon::debug('DB切断したよ');
System_Daemon::stop();
ということで、リンク先とほとんど同じソースを提示してしまうわけですが、私なりのハマリポイントを挙げておくと、デバッグログが出なかったことです。PEARのLogでPEAR_LOG_DEBUGという定数を指定しているので、PEARのLogの方ではデバッグログも出す気満々待ち構えているのですが、System_Daemonの方でlogVerbosityを指定しないと、ダメなのです。ちなみに7がデバッグ相当の値。
ちなみに、ログはSystem_Daemonのメソッドを使わなくても、$logger->debug()という風にPEARのLogに直接吐き出すことも可能で、その場合はlogVerbosityの指定は無関係です。
System_Daemon::iterate(5)というのは、5秒待ってから次の処理をやるという意味で、これはCPU負荷の観点から待ち時間を入れた方が良いというのと、iterate()の処理で余計な内部キャッシュをクリアするといったこともやるようなので、新しいループに入る度、または出る度にやっておいた方が良さそうです。
起動は作ったPHPファイルを、ふつうにphpコマンドの引数として渡すだけでOK。終了はpsコマンドでプロセス番号を特定してkillします。ログは上記の例では、作ったPHPファイルと同じ場所にhoge.logというテキストファイルとして出力しますが、PEARのLogで出来ることなら何でもOKなので、syslogに出したり、メールを送ったりということも可能でしょう。
また上記の例では実行ユーザを指定していないので、rootで/var/logにpidファイルを作成しようとします。そのため、root権限で起動しなければなりません。実行ユーザを指定する場合は、$options配列でappRunAsUIDとappRunAsGIDを指定すれば良く、pidファイルの作成場所はappPidLocationで指定できます。
私は、System_Daemonを使って、MySQLのふつうのテーブルとして作ったQueueを見て、順に処理するというデーモンを作りました。MySQLをふつうに使ってQueueを実現する方法は、MySQL を使ったお手軽メッセージキュー実装 – ドワンゴ 研究開発ブログを参照ください。