Webアプリケーションの中には、ときどき時間がかかる処理をしないといけない部分があります。アップロードされた画像のサムネイルを多数生成するときや、クライアントからのリクエストに応じてさらにリモートのサーバからファイルを取得してきたりするとき、ふつうに作るとユーザは処理が終わるまでの数秒~数十秒間待たされるのでイライラしてきます。
こんなときには昨年のYAPCでLiveJournal: Behind The Scenesの中で紹介されている、perlで書かれた非同期処理サーバのGearmanが役に立ちます。Webアプリケーションから時間のかかる処理を別プロセスで動いているGearmanに依頼しておくことで、時間のかかる処理が終わるまで待つことなくユーザにレスポンスを返すことができます。
ほんとうは、時間のかる処理の性質と、必要とされる機能に応じてGearmanとTheSchwartzとを使い分けるべきです。細かいことは web2.0 時代のジョブキューサーバー Gearman と TheSchwartz の関係について - TokuLog 改めChumbyとどきました日記 をご参照ください。
GearmanはperlからだけでなくPHPやrubyやpythonにもポーティングされていて、ジョブを追加することができます。
Firefoxからも直接追加したいことがあったので、javascriptでGearmanにジョブを追加するコードを書きました。var Pack = {
VERSION: "0.0.3",
_range: function (n) {
var a = [];
while (n--) { a.push(n) }
return a;
},
_bytes: function (value, bytes) {
return this._range(bytes).map( function(n) {
return String.fromCharCode( (value & (0xFF << ( 8 * n )) ) >> (8 * n) );
} );
},
_16: function (n) { return this._bytes(n, 2) },
_32: function (n) { return this._bytes(n, 4) },
N: function (n) { return this._32(n).join(""); },
n: function (n) { return this._16(n).join(""); },
v: function (n) { return this._16(n).reverse().join(""); },
C: function (n) { return String.fromCharCode( n ); }
};
function dispatch_background (method, uniqid, arg, host, port ) {
host = host || "localhost";
port = port || 7003;
var sts = Components.classes["@mozilla.org/network/socket-transport-service;1"].
getService(Components.interfaces.nsISocketTransportService);
var t = sts.createTransport (null, 0, host, port, null );
var os = t.openOutputStream(0,0,0)
var payload = [method, uniqid, arg].join("\0");
var data = [
'',
[
"REQ",
Pack.N(18), // submit_job_bg
Pack.N( payload.length ),
payload
].join("")
].join( "\0" );
os.QueryInterface(Components.interfaces.nsIAsyncOutputStream);
os.write(data, data.length)
os.close()
}
// dispatch_background("ticket", uniqid, '{"name":"ku"}');
GearmanのサーバはTCPのポート7003をlistenしています。ここにGearman/Util.pmの
sub pack_req_command {
my $type_arg = shift;
my $type = $num{$type_arg} || $type_arg;
die "Bogus type arg of '$type_arg'" unless $type;
my $arg = $_[0] || '';
my $len = length($arg);
return "\0REQ" . pack("NN", $type, $len) . $arg;
}を参考に、同じパケットを作って送れば、どんな言語からでもジョブを追加することができます。
トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。
http://labs.gmo.jp/mt/mt-tb.cgi/219
comments