Home > アーカイブ > 2014-08

2014-08

PhpStorm から Vagrant VM の PHP アプリケーションをリモートデバッグする(Web & CLI)

この記事の所要時間: 1011

logo_phpstorm

PhpStorm から Vagrant で構築した VM の PHP アプリケーションをリモートデバッグする方法です。Web アプリケーションだけでなく、CLI アプリケーションでもリモートデバッグできるように設定していきます。

VM スペック

  • 192.168.33.41 を private network で設定
  • PHP + Xdebug がインストール済み
  • ホストと VM は、synced folder でディレクトリを共有(/path/to/src -> /share)

0. Xdebug によるリモートデバッグの仕組み

リモートデバッグを設定する前に PhpStorm と Xdebug がどのように通信するかを見ておきます。これを理解しておくと設定がスムーズです。

下記は、Xdebug の公式サイトに掲載されている図です。ここでは、左の「IDE」が PhpStormが起動しているホスト、右の「PHP/Xdebug」が Vagrant で構築した VM と考えて下さい。

VM に HTTP リクエストが来て、PHP スクリプトの実行がはじまると、PHP/Xdebug が IDE(xdebug.remote_hostで設定したホスト)に DBGP connect の通信を行います。PhpStorm ではこの通信を受け取り、以後は DBGP で相互に通信してリモートデバッグを実現します。

xdebug-remote-debug

ここで大切なのは、PHP/Xdebug(VM)から、PhpStorm へ DBGP connect の通信が来るという点です。これは Web でも CLI でも同じで、PHP スクリプトが VM で実行されると PhpStorm へ DBGP connect が送られてきて、リモートデバッグを開始することができます。(xdebug.remote_autostart= Onを設定した場合)

もし、うまく動かない場合などは、この点を意識して調査すると良いです。

では、実際に設定を行っていきましょう。

1. VM での設定

まず、VM にインストールされている PHP にリモートデバッグ用の設定を行います。通常は、VM を構築する際に実行するプロビジョニングに以下を含めておきます。

Xdebug が必要になるので、下記のコマンドなどで、インストールしておいて下さい。

$ yum -y install php-pecl-xdebug

1-1. php.ini(xdebug.ini)

Xdebug の設定を php.ini 等で以下のように設定します。

xdebug.remote_enable = On
xdebug.remote_autostart = On
xdebug.remote_host = 192.168.33.1
  • xdebug.remote_enableで、リモートデバッグを有効にします。
  • xdebug.remote_autostartを On にすることで、リモートデバッグが常に開始されるように設定します。任意のタイミングだけ開始することもできるのですが、開発環境なので、VM側では常に開始されるようにしておき、実際にデバッグを行うかどうかは PhpStorm 側で操作します。
  • xdebug.remote_hostで、デバッグクライアントの IP を指定します。Vagrant の private network で 192.168.33.xxxを設定しているので、ホスト側の IP として192.168.33.1を設定しています。

1-2. 環境変数

CLI アプリケーション(phpunitコマンドでのテストを含む)でのデバッグを行うために、環境変数PHP_IDE_CONFIGを設定します。

CLI アプリケーションを実行するユーザでPHP_IDE_CONFIG環境変数を定義したいので、ここでは、vagrant ユーザの ~/.bashrc に設定しておきます。

192.168.33.41の部分には、VM の IP を指定しておきます。

export PHP_IDE_CONFIG="serverName=192.168.33.41"

もし、apache ユーザで CLI アプリケーションを実行するなら、httpd.conf 等の SetEnv などで設定すると良いでしょう。

2. PhpStorm での設定

PhpStorm でリモートデバッグクライアントの設定を行いましょう。

2-1. PHP Remote Debug

まず、メニューの [Run] – [Edit Configurations…] をクリックして、[Run/Debug Configurations] ダイアログを開きます。

次にダイアログ左上にある [+] をクリックして、[PHP Remote Debug] を選択します。すると、下記のように PHP Remote Debug の設定フォームが表示されます。ここでリモートデバッグの設定を入力していきます。

phpstorm-run-debug-configurations

Name には、この設定の名称を指定します。ここではVagrantとしています。

Servers には、PHP サーバをプルダウンで選択するのですが、まだ設定が無いので、後ほど設定します。

Ide key は、今回は設定不要なのですが、何かしら値が必要なので、ダミー値を入力します。

2-2. Servers

Servers にサーバを追加するために、Servers のプルダウンメニュー横にある「…」ボタンをクリックします。クリックすると、[Servers] ダイアログが開きます。

[Servers] ダイアログでは、PHP アプリケーションが動作しているサーバの情報(ここでは Vagrant VM)を設定します。

ダイアログ左上にある [+] をクリックして、新規サーバを入力します。

Name には、名称を入力します。名称は何でも良いのですが、ここでは VM の IP を入力します。この値は、VM で設定した環境変数PHP_IDE_CONFIGの中で記述するserverName=の値と同じ内容にする必要があります。

Host には、VM の IP を入力します。

Use path mappings にチェックを入れます。ここでは、ローカルのファイルパスと VM でのファイルパスをマッピングを設定します。

この Vagrantfile では、ローカルの /path/to/src を VM 上では /share というディレクトリにマウントしているので、File/Directory/path/to/src を選択し、その右にある Absolute path on server/share と入力しておきます。

設定例は下記になります。

phpstorm-servers

[OK] をクリックすると Servers ダイアログが閉じます。この時に [Run/Debug Configurations] では、Servers には、現在設定したサーバが選択されています。

phpstorm-run-debug-configurations-done

最後に [OK] をクリックすると、設定が保存され、ダイアログが閉じます。これで設定は完了です。

3. 動作確認

では、実際にリモートデバッグを試してみましょう。

PhpStorm でリモートデバッグを有効にするには、[Run] – [Start Listen for PHP Debug Connections] をクリックします。クリックすると [Stop Listen for PHP Debug Connections] という表示に切り替わります。この状態で、再度クリックするとリモートデバッグが停止します。

今回の設定では、VM 側は常にリモートデバッグ可能な状態になっているので、PhpStorm でのこの操作でリモートデバッグを行うかどうかを切り替えることができます。

リモートデバッグが動作しているか確認するのに、[Break at first line in PHP scripts] にもチェックを入れておきます。

phpstorm-start-listen-for-php-debug-connections

3-1. Web アプリケーション

では、ブラウザから、VM にある PHP スクリプトにアクセスしてみましょう。(ここでは、Laravel アプリケーションを動かします。)

http://localhost/ にアクセスすると、処理が停止して、PhpStorm のデバッガが起動しました。

これは [Break at first line in PHP scripts] にチェックが入っているためで、一番はじめの行で処理が停止するようになっています。[Step Over] や [Step into] で、順にコードを実行して、PhpStorm 上で実行されている行が正しく遷移するか確認すると良いでしょう。

phpstorm-remote-debug-web

確認が終わったら、[Run…] でコードを実行する、もしくは [Stop] で停止させましょう。

3-2. CLI アプリケーション

CLI アプリケーションについてもリモートデバッグができるか確認しましょう。

vagrant ssh で、VM にログインして、何か PHP アプリケーションをコマンドラインで起動します。ここでは php artisanコマンドを実行します。

$ php artisan

すると、Web アプリケーションと同じく、はじめに実行される行で処理が停止し、PhpStorm のデバッガに制御が移ります。

phpstorm-remote-debug-cli

PHPUnit なども実行して、同様になるか確認しておくと良いでしょう。

これで、Web でも CLI でも PHP アプリケーションでリモートデバッグができるようになりました。あとは順に実行するなり、任意のコードにブレイクポイントを仕掛けるなり、デバッグを行うことができます。

なお、動作確認用にチェックしておいた [Break at first line in PHP scripts] ですが、アプリケーション実行の度に停止するのは面倒なので、普段はチェックは外しておきましょう。

4. トラブルシューティング

4-1. デバッガが起動しない

おそらく基本的な設定ミスなので、手順を再確認します。

  • xdebug 関連の設定変更後に Apache/php-fpm の再起動を行う
  • PhpStorm で[Start Listen for PHP Debug Connections]を行う

4-2. デバッガは起動するのに、ステップ実行できない

PhpStorm の [Servers] 設定のパスマッピングの設定を見直します。

4-3. Cannot accept external Xdebug connection: Cannot parse the value of ‘$_SERVER[‘PHP_IDE_CONFIG’]’

CLI アプリケーションでリモートデバッグを行う際に発生しました。
環境変数PHP_IDE_CONFIGが正しくセットされていなかったので、VM 側の設定を見直します。

さいごに

PhpStorm から Vagrant で構築した VM へのリモートデバッグ設定について見てきました。

はじめは面倒に見えますが、慣れてくればかなり楽に設定できます。VM 側の設定は、プロビジョニングに記述しておくと良いでしょう。

やはり、処理の流れはデバッガを使った方が掴みやすいので、ぜひ活用してみてください。

参考

http://www.jetbrains.com/phpstorm/webhelp/run-debug-configuration-php-remote-debug.html
http://www.karakaram.com/phpstorm-vagrant-remote-debug
http://blog.jetbrains.com/webide/2012/03/new-in-4-0-easier-debugging-of-remote-php-command-line-scripts/

  • コメント (Close): 0
  • トラックバック (Close): 0

Laravel の Queue で非同期処理を実装する(beanstalkd / IronMQ / SQS)

この記事の所要時間: 1654

Laravel で実装されている Queue について見てみました。

laravel

Laravel では Queue を使うことで、時間がかかる処理や、時間差で実行したい処理を非同期で実行することができます。

Laravel 4.2 の Queue では、以下の 5 つのキュードライバをサポートしています。

  • sync
  • Beanstalkd
  • Amazon SQS
  • IronMQ
  • Redis

ここでは、sync、Beanstalkd、IronMQ、Amazon SQS について試してみました。

Laravel での設定

Laravel で Queue を使うには、app/config/queue.phpにて、利用するキューエンジンの選択、設定を行います。

もちろん他の設定と同じく、app/config/local/queue.phpapp/config/production/queue.phpなど、環境に応じて設定を切り替えることも可能です。

下記が設定例です。defaultでは利用するキュードライバを指定します。指定できる値は、sync, beanstalkd, sqs, iron, redis の 5 種類です。

connectionsキーでは、それぞれのドライバについて接続情報を指定します。下記では、beanstalkdの接続情報を指定しています。

return [
    'default' => 'beanstalkd',
    'connections' => [
        'beanstalkd' => [
            'driver' => 'beanstalkd',
            'host' => 'localhost',
            'queue' => 'default',
            'ttr' => 60,
        ],
    ],
];

キューへジョブを登録

キューへのジョブを登録するには、Queueクラスのpushメソッドを使います。

第一引数にはジョブを実行するワーカーのクラス名を、第二引数にはワーカーに渡すパラメータを指定します。

use CarbonCarbon;

Queue::push('MyWorker', ['message' => 'Hello!', 'date' => Carbon::now()]);

ここでは、ワーカーのクラス名のみを指定しているため、ジョブを実行する際はfireメソッドが呼ばれます。他にもMyWorker@doJobとすることで任意のメソッドを実行したり、クロージャを渡して、そのクロージャをワーカーとして実行したりできます。

詳しくはドキュメントを参照してください。

http://laravel.com/docs/queues
http://laravel4.kore1server.com/docs/42/queues

ワーカーの実装

ジョブを処理するワーカーとしてMyWorkerクラスを実装します。ワーカーは特定のクラスを継承する必要はなく、 POPO(Plain Old PHP Object)で良いです。

MyWorkerクラスにはfireメソッドを実装します。ジョブがキューに登録されると、リスナーからこのメソッドが呼ばれます。

第一引数にはジョブインスタンス、第二引数では、Queue::push()の第二引数で指定したパラメータが渡されます。ただ、このパラメータはジョブに入る時にjson_encode()されるので、オブジェクトのインスタンスはプロパティの連想配列となります。

下記の実装では、渡されたパラメータを元に文字列を生成して、echoで標準出力へ出力しているだけです。

ジョブが正常に完了したら、delete()メソッドで、ジョブを削除しておきます。これを行わないと同じジョブが何度も実行されています。

<?php
use CarbonCarbon;
use IlluminateQueueJobsJob;

class MyWorker
{
    /**
     * @param Job $job
     * @param array $data
     */
    public function fire(Job $job, array $data)
    {
        echo sprintf('[%s] %s at %s', Carbon::now(), $data['message'], $data['date']['date']) . PHP_EOL;
        $job->delete();
    }
}

キューの監視

キューを監視してワーカーを起動するリスナーを起動します。

Laravel では artisan コマンドですでに用意されているのでこれを利用します。

php artisan queue:listenコマンドを実行すると、キューを監視状態になります。この状態でキューにジョブが登録されていると、自動でワーカーが起動して処理が実行されます。

$ php artisan queue:listen

この状態でジョブが登録されると下記のように出力されます。

$ php artisan queue:listen
[2014-08-14 16:52:35] Hello! at 2014-08-14 16:52:34.000000
Processed: MyWorker

このプロセスが終了しているとキューにジョブが登録されても実行されないので、supervisor や monit などで常時起動するように設定しておくと良いでしょう。

一定時間後に実行するジョブ

Queue::push()で登録したジョブは、リスナーが感知するとワーカーが起動して実行されます。

それとは別に、Queue::later()というメソッドを使うと、一定時間経過後に実行するジョブを登録することができます。

第一引数には、ジョブの実行を開始する時間を指定します。数値を渡すと秒数として認識され、その秒数が経過した際にジョブが実行されます。Carbonクラスのインスタンスを渡すとCarbonクラスで指定された日時に実行されるジョブとして登録されます。

第二引数と第三引数は、Queue::push()の第一引数と第二引数と同じです。

下記の例では、10秒後に実行されるジョブを登録しています。

Queue::later(10, 'MyWorker', ['message' => 'Delayed', 'date' => Carbon::now()]);

リスナー側では下記のような出力になります。[]内の日時と、atの後ろの日時で 10 秒ずれていることが分かります。

$ php artisan queue:listen
[2014-08-14 16:52:45] Delayed at 2014-08-14 16:52:34.000000
Processed: MyWorker

これはローカルの beanstalkd での実行なのでずれが無いですが、IronMQ を利用した際は、数秒のずれがありました。多少のずれは発生するので、それを認識した上で利用すると良いでしょう。

サポートしているキュードライバ

Laravel でサポートしているキュードライバ(Redisを除く)を見てみましょう。

sync

デフォルトで指定されているドライバです。

仕組みとしてはキュー、ワーカーの流れを通るのですが、ジョブが登録されると、即時にワーカーが実行されます。

非同期処理にはならないので、実際にキューを使う場面では、他のドライバを利用する必要があります。

Beanstalkd

Beanstalkd は、オープンソースのキューイングシステムです。

利用するには、Beanstalkd 自体のインストールが必要になります。

Beanstalkd は、yum などパッケージでも公開されているので、利用するプラットフォームごとに選択してインストールすると良いです。

ここでは OSX 環境を想定して、Homebrew でインストールします。

$ brew install beanstalkd

beanstalkd を起動します。デフォルトではポート11300で待ち受けます。

$ beanstalkd

なお、beanstalkd は、デフォルトではキューの情報を永続化しません。このままだと beanstalkd が落ちるとキューの情報が消えてしまうので、本番環境などで運用する際は、永続化するように設定を行うのが良いです。

http://kr.github.io/beanstalkd/

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。pda/pheanstalk は、3.x がリリースされていますが、Laravel 4.2 は、2.x 系にしか対応していないので、バージョン番号に注意して下さい。

"require": {
  "pda/pheanstalk": "~2.1.0"
}

IronMQ

Iron.io が提供しているメッセージキューサービスです。

ブラウザから登録するだけで利用することができます。基本は有償サービスなのですが、無料プランが用意されており、1,000,000APIリクエスト/月まで利用することができます。

グラフィカルな管理画面が用意されており、キューの状況などが分かりやすいのが良いです。

Heroku の Addon としても提供されているので、Heroku へデプロイするなら簡単に連携することができます。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "iron-io/iron_mq": "~1.5.1"
}

下記が Heroku 環境で IronMQ を利用する際の設定例です。Heroku では、接続情報が環境変数で提供されてるので、それらをtokenprojectに設定しています。

return [
    'default' => 'iron',
    'connections' => [
        'iron' => [
            'driver' => 'iron',
            'host' => 'mq-aws-us-east-1.iron.io',
            'token' =>  getenv('IRON_MQ_TOKEN'),
            'project' => getenv('IRON_MQ_PROJECT_ID'),
            'queue' => 'sample',
            'encrypt' => true,
        ],
    ],
];

AWS US-EastAWS EU-WestRackspace ORDRackspace LONのインスタンスを利用することができます。日本国内のインスタンスは存在しないので、国内のアプリケーションからキューを登録する場合はレイテンシが気になるかもしれません。

http://www.iron.io/

SQS

AWS のメッセージキューサービスです。

こちらも管理画面からキューを作成するだけで利用することができます。有償サービスですが、無料枠が用意されており、100万件キューイングリクエスト/月まで無料で利用することができます。

東京リージョンを利用できるので、アプリケーションサーバが国内にあるなら利用しやすいですね。

Laravel で利用する際は、composer で下記のパッケージを追加しておきます。

"require": {
  "aws/aws-sdk-php-laravel": "1.*"
}

設定例は下記です。ここでは、アクセスキーやシークレット、エンドポイントURL を環境変数で渡しています。AWS ではおなじみですが、regionにキューを作成したリージョンを指定するのを忘れないようにしましょう。

    'default' => 'sqs',
    'connections' => [
        'sqs' => [
            'driver' => 'sqs',
            'key' => getenv('AWS_ACCESS_KEY_ID'),
            'secret' => getenv('AWS_SECRET_ACCESS_KEY'),
            'queue' => getenv('AWS_SQS_URL'),
            'region' => 'ap-northeast-1',
        ],
    ],

http://aws.amazon.com/jp/sqs/

ユニットテスト

キューにジョブを登録する側のテストについてです。

QueueクラスをshouldReceiveメソッドでモック化して、テストするのが手軽です。

<?php
use CarbonCarbon;

/**
 * Class QueueTest
 */
class QueueTest extends TestCase
{
    /**
     * @test
     */
    public function queuePush()
    {
        $now = Carbon::create(2014, 8, 13, 12, 34, 56);
        Carbon::setTestNow($now);

        Queue::shouldReceive('connected')->once();
        Queue::shouldReceive('push')->once()->with('MyWorker', ['message' => 'Hello!', 'date' => $now]);
        Queue::shouldReceive('later')->once()->with(10, 'MyWorker', ['message' => 'Delayed', 'date' => $now]);

        $this->client->request('GET', '/queue/push');

        $this->assertTrue($this->client->getResponse()->isOk());
    }
}

サンプルアプリケーション(Heroku)

このエントリの内容を実装したサンプルアプリケーションを github に公開しています。

コード自体はシンプルで、http://localhost/quque/push にアクセスするとジョブがキューに登録されます。あとは php artisan queue:listen コマンドでジョブが実行されます。

Heroku で試せるように、heroku_create というシェルスクリプトで、heroku 関連のコマンドを記述しています。このコマンドを流せば、Heroku アプリケーションが構築されます。

Heroku でのポイントは、`Procfile`で、ワーカープロセスとしてリスナーを起動するという点です。

web: vendor/bin/heroku-php-apache2 public/
worker: php artisan queue:listen

このアプリケーションを Heroku にデプロイすると、web(ジョブをキューに登録する側)、worker(リスナー)の Dyno が構築されます。

あとは Heroku の管理画面で worker の Dyno 数を 1 にすると、web 経由で登録したジョブが worker によって実行されるようになります。

https://github.com/shin1x1/laravel-queue-sample

さいごに

Laravel の Queue について見てきました。

最後に、どのドライバを使うかについてですが、開発環境では beanstalkd を利用するのが手軽で良いでしょう。ローカルにインストールするので動作も速いです。

本番環境では、要件によりけりですが、国内にアプリケーションサーバがあるなら SQS、Heroku など US リージョンを利用するなら IronMQ が良さそうです。

もちろん、自前で beantalkd や Redis を立てるのも良いですが、利用できるなら、ありものを利用するのが楽ですね。

このように、開発環境と本番環境とでドライバを変えても、コード側は一切変更する必要が無いというのは、よく出来ていますね。

参考

blog.ISHINAO.net | Laravel 4でキューを使ってみる
laravel – キュードライバにbeanstalkdを使用する – Qiita

  • コメント (Close): 0
  • トラックバック (Close): 0

Home > アーカイブ > 2014-08

検索
フィード
メタ情報

Return to page top