PHPで並行処理をしたい個所が出てきた。

PHP: Hypertext Preprocessor


データベースに挿入するデータがタイムスタンプとそれに紐づく値で、データを挿入する順番を気にしなくても良いログのようなものだ。


タイムスタンプは必ず0時0分0秒のものにして、重複する場合は挿入しないという仕様なので、

片っ端からデータを突っ込もうとしてもデータベースに過剰にデータが挿入されるということはない。


Go言語であればゴルーチンという素敵な仕様があるけれども、

Go言語でsyncパッケージを使ってみる


PHPには平行処理を気軽に出来る仕組みはないか?と探してみたところ、

ジョブファイルを作成して、execでジョブファイルを実行すれば良いそうだ。

PHP: exec - Manual


/path/to/dir/job.php

<php
//集計に関する処理

exe.php

<php
$cmd = "nohup php /path/to/dir/job.php > /dev/null &";
exec($cmd);  //これでjobが並行で実行される

//何らかの同期的な処理を書く

※nohupでバックグラウンド実行。> /dev/null &を追加することで結果の扱いはスルーする


こんな感じで並行処理ができた。

この書き方の欠点といえば、ジョブの方の結果をメインのプロセスの方に返せないということだ。

ここらへんはGo言語のゴルーチン(チャネル)は本当に良くできている。




ここで一つ問題が生じた。

GoogleのOAuthを介して、Google Analytics APIからデータを取得するジョブを作成する時だ。


メインのプロセスでGoogleのOAuthでログインを行った後に取得したアクセストークンを利用する場合だ。

アクセストークンはセッションに格納されるけれども、並行で実行したジョブ内ではメインのプロセスのセッションが利用できない。


ここで一つセッションの参照という工夫をする必要があった。


/path/to/dir/job.php

<php
//メインのプロセスのセッションを共有する
session_id($argv[]);
session_start();

//集計に関する処理

exe.php

<php
$cmd = "nohup php /path/to/dir/job.php " . session_id() . " > /dev/null &";
exec($cmd); 

//何らかの同期的な処理を書く

メインのプロセスのジョブの第一引数にセッションIDを指定して、ジョブファイルの方でセッションIDを受け取りセットするという処理を追加したことで、セッションに格納された値をジョブ内でも使用できるようになった。


後はジョブ内の結果をメインのプロセス内で使えるようにするだけれども、これはまだ必要に迫られていないので触れていない。

PHPでジョブの結果を待つ仕組み等を考えるのであれば、Go言語やNode.jsを素直に使った方が良さそうだな。

Socket.IOのチャットアプリで誰が入力中なのかを出力したい