Ethnam+PHPUnitでAppManagerのユニットテストをしたい日記

Hello_HelloManagerTest

 Ethna の後継プロジェクトとして DQNEO さんが開発している Ethnam というプロジェクトがあり、Ethna で書かれた職場システムをメンテしている立場の私としても、将来を見据えて(PHP5.4以降ではおそらく現行のEthnaが動かないので)試しにEthnamで何か新規案件を作ってみようかな、という感じで触ってます。

 それで表題の件ですが、Ethnaにはsimpletestを使ったユニットテスト機能が組み込まれていますが、Ethnamは現在そこまで至っていません。
 ただ、開発するのであればやっぱりユニットテストはやりたいので、せめてモデル部分のロジックを書くAppManagerに対するテストはできるようにしたいと考えました。
 また、Ethnamは将来的にはPHPUnitを導入する予定とのことなので、こちらもテストにはPHPUnitを使うことにします。

 以下、試しにやったこと。



続きを読む

Kindle4用TINAMIイラストビューア「Papetina」を公開しました日記

 お久しぶりです。
 趣味のプログラミングの一環として、Amazon Kindle4 用TINAMIイラストビューア・Papetina を作ってました。日本未発売のKindle4と、pixivではなくTINAMIのマッシュアップという、ものすごいニッチなところを狙ったWebサービスです。
 元々の製作動機が最近使ってなかったKindle4の最活性化なので、自分しか使わないんじゃないかと思います。それでいいのです(自己肯定)。

 このサイトを作るにあたって得られた知見をまとめてみます。



続きを読む

System_Daemonを使ってNet_GearmanのWorkerをバックグラウンドで動かす

 前回のPHPで書いたGearman_Workerのプログラムをバックグラウンドで動かそうとするとプロセスが止まってしまう件ですが、これを解決する方法を探していて見つけたのが、PEARのSystem_Daemonというモジュールです。
 これは要するに、PHPでデーモンみたいな動きをするプログラムを書けるよ! というマニアックなモジュールで、これを使えばPHPのCLI版のプログラムをバックグラウンドで動かし続けることが可能になります。個人的にはPHPはプロセス制御するには(perlなどと比べると)不向きな言語だと思っているので、よくこんなのPHPで作ったよなあという感じ。

 System_Daemonを使ってWorkerを動かすようにしたのが以下のプログラムです。

gearman_worker.php

#!/usr/bin/php -q
< ?php
ini_set('include_path', ini_get('include_path').':..');

error_reporting(E_ALL);
require_once "System/Daemon.php";
require_once 'Net/Gearman/Worker.php';

System_Daemon::setOption("appName", "Gearman_worker");
System_Daemon::setOption("appDir", dirname(__FILE__));
System_Daemon::start();

$servers = array('localhost:7003');
try {
        $worker = new Net_Gearman_Worker($servers);
        $worker->addAbility('hello');
        $worker->beginWork();
} catch (Net_Gearman_Exception $e) {
        System_Daemon::log(System_Daemon::LOG_INFO, $e->getMessage());
}

System_Daemon::stop();
?>

 実行すると、System_Daemon::start() の後に書いたコードがバックグラウンドで実行されます。
 実行時には(ubuntuでは)/var/log配下にログファイル(この場合はGearman_worker.log)を作るので、ここにアクセスするためにスクリプトはroot権限で実行する必要があります。
 またSystem_Daemonには、/etc/init.d/ にプロセスの起動・終了スクリプトを自動的に作ってくれるちょっとお茶目な機能もあります。スクリプトの作り方はSystem_Deamonのサイトに詳しく書かれているので、必要に応じてどうぞ。面白いモジュールですね。

 なお、ここまで書いておいて何なのですが、業務システムで使うならWorkerはやっぱり枯れているperlで書いた方が安全だよなあという気持ちになっています(オチ)。

Net_Gearmanを使ってPHPでGearman Workerを作る

 現在ライブドアの4Gbps本を購入して読んでますが(いきなり)、第2章で紹介されていた Gearman を使ったキューイングシステムがたいへんに便利そうでした。なので、積極的にマネしていきたいと思ってます。
 4Gbps本には perl を使ったサンプルが紹介されていましたけど、現在の業務では主に PHP を使っているので、Gearman の PHP 実装を使ったワーカーやクライアントが作れないか調べているところです。以下、今のところの調査報告。

インストール

Server

 Gearman のサーバ (gearmand) は、Ubuntu では apt-get で拾うことができるので、今回はそれを使用しました。

#sudo apt-get install gearman-server
/etc/default/gearman-server の「ENABLED="false"」を "true" に変更
#sudo /etc/init.d/gearman-server start

Net_Gearman

 PEARのモジュールとして公開されている Net_Gearman をインストールします。

#sudo pear install Net_Gearman-0.2.3

 Net_Gearmanは、github でも公開されています。このページに書かれているお手本を見れば、使い方は判ると思います。

Workerの作成

 Net_Gearman は、ワーカーと実際に処理を実装するジョブを別のソースに分けて書く必要があります。
 Net_Gearman_Workerでワーカーを作り、addAbilityでジョブ名を登録、beginWorkでクライアントからのジョブの待ち受けを開始、みたいな流れ。

gearman_worker.php

< ?php
require_once 'Net/Gearman/Worker.php';
$servers = array('localhost:7003');
try {
    $worker = new Net_Gearman_Worker($servers);
    $worker->addAbility('hello');
    $worker->beginWork();
} catch (Net_Gearman_Exception $e) {
    echo $e->getMessage() . "\n";
    exit;
}
?>
#php gearman_worker.php

なお、「php gearman_worker.php &」とやってバックグラウンドで動作させるとそこでプロセスが止まってしまい、フォアグラウンドに戻してあげないとクライアントからの呼びかけに応答してくれませんでした。CLI版PHPの仕様?

Jobの作成

 ワーカーから呼び出されるジョブですが、

  • Net/Gearman/Job ディレクトリの配下に、
  • ジョブ名.php というファイル名で、

 記述する必要がある様です。Net/Gearman/Job は、ワーカープログラムから見える場所(includeのパス)に存在していないといけません。
 なので、とりあえず今回は gearman_worker.php を置いたディレクトリに Net/Gearman/Job というディレクトリを作り、その下に hello.php を置くようにしました。

 また、ジョブは

  • Net_Gearman_Job_Common クラスを継承した、
  • Net_Gearman_Job_ジョブ名 という名前のクラス

 である必要があります。そのクラスの run という関数(メソッド)に、実際の処理を書きます。

Net/Gearman/Job/hello.php

< ?php
require_once 'Net/Gearman/Job/Common.php';

class Net_Gearman_Job_hello extends Net_Gearman_Job_Common
{
    public function run($arg)
    {
            echo "Hello, " . $arg['name'] . "!\n";
    }
}
?>

Clientの作成

 クライアントはNet_Gearman_Clientを作ってジョブ名をメソッドとして記述することで、指定したジョブをバックグラウンドで実行します。ジョブには配列の形でデータを渡せます(内部的には JSON に変換しているらしい)。

gearman_client.php

< ?php
require_once 'Net/Gearman/Client.php';
$client = new Net_Gearman_Client('localhost:7003');
$client->hello(array('name' => 'World'));
?>

 gearman_client.php を実行し、gearman_worker.php を実行しているコンソールに「Hello, World!」と表示されれば、我々の勝ちです。

 とりあえずこんな形で PHP でワーカー+ジョブとクライアントを記述できますが、ワーカーをバックグラウンドで動かすと止まっちゃうので、そのままではジョブを PHP で書くのはあまり現実的ではないかなと思いました。
 クライアントは上記の通りえらい簡単に書けるので、ワーカー+ジョブはperlで、クライアントはPHPでという形で運用するのが無難かと思います。perl+PHPの運用は、こちらの記事がとても参考になります。

 (次回予告:System_Daemonを使ってNet_GearmanのWorkerをバックグラウンドで動かす)

4Gbpsを超えるWebサービス構築術
伊勢 幸一 池邉 智洋 栗原 由樹 山下 拓也 谷口 公一 井原 郁央
ソフトバンククリエイティブ
売り上げランキング: 192