Jonkで作るおれおれJobQueueフレームワーク
こんにちわこんにちわ!YAPC::Asia 2010でベストスピーカー賞(次点)を頂いた nekokak です。
今回は拙作 Jonk でオレオレJobQueueフレームワークを作るお話をします。
はじめに
なぜJonkをつくったのかについては、JobQueueManagerについてを
ご覧頂ければと思います。
簡単に言うと、やりたい事って案件によりけりだから、自分でその案件にあったJobQueueフレームワークつくれたほうがいいよね!
です。
install
$ cpanm Jonk
だけです。依存モジュールはTry::Tinyというモジュール一個だけなので、
全く問題無く入るでしょう。
依存モジュールが殆ど無いのがJonkの売りの一つです。
JobQueueを管理するためだけに、よくわからないORMがインストールされてしまったり
よく分からないモジュールがインストールされるのってやじゃないですか:)
Jonkが依存しているTry::TinyはPlackでも利用されている由緒正しきモジュールなのでご安心下さい。
setup
JonkはJobの管理でRDBMSを利用します。
対応しているRDBMSはMySQL/PostgreSQL/SQLiteの3種類です。
Jonk.pmのPOD中のSCHEMAセクションに各RDBMS毎のschemaがあるので、それをつかってDBを作ってください。
database名などはご自由に。
以上でJonkを使う準備が整いましたので、さっそオレオレJobQueueフレームワークを作りましょう。
簡単クローラーを作る
よくある単純なクローラーを作ってみます。
超単純なので実際に作る場合は色々考えて作ってください。
fetchしてくるurlをenqueueする
まずfetchしてくるURLを登録するクライアントを作成します。
$ cat ./client.pl #! perl use strict; use warnings; use DBI; use Jonk::Client; my $url = shift or die '$0 <url>'; my $dbh = DBI->connect('dbi:SQLite:./sample.db','',''); my $client = Jonk::Client->new($dbh); $client->enqueue('MyFetcher', $url);
クライアントスクリプトとしてはこんな感じで
$ perl ./client.pl http://example.com/
とするだけで、http://example.com/
をクロール対象とするJobをenqueueすることができます。
worker起動スクリプトを作成する
workerのモデルとしては、forkモデルで複数プロセスでfetchしてくる感じです。
forkでのプロセス管理でParallel::Preforkを利用します。
$ cat ./worker.pl use strict; use warnings; use Parallel::Prefork; use DBI; use Jonk::Worker; use MyFetcher; my $pm = Parallel::Prefork->new({ max_workers => 10, trap_signals => { TERM => 'TERM', HUP => 'TERM', }, }); while ($pm->signal_received ne 'TERM') { $pm->start and next; my $dbh = DBI->connect('dbi:SQLite:./sample.db','',''); my $jonk = Jonk::Worker->new($dbh => {functions => [qw/MyFetcher/]}); while (1) { if (my $job = $jonk->dequeue) { MyFetcher->work($job); } else { sleep(3); # wait for 3 sec. } } $pm->finish; } $pm->wait_all_children();
worker起動スクリプトとしてはこんな感じです。
これで10子プロセスが生成され、10人のworkerが随時Jonkからjobを取り出し
MyFetcherにJobの情報を渡して処理させます。
MyFetcherはこんなかんじでしょうか
package MyFetcher; use strict; use warnings; use LWP::UserAgent; sub work { my ($class, $job) = @_; my $ua = LWP::UserAgent->new; my $res = $ua->get($job->{arg}); print $$; if ($res->is_success) { print $res->decoded_content; # or whatever } else { print $res->status_line; } } 1;
簡単でしょ?
今回は超簡単なサンプルスクリプトでご説明しました。
サンプルコードも
https://github.com/perl-users-jp/perl-advent-calendar/tree/master/2010/hacker/jonk_sample/
に置いておきましたのでどうぞ。
このようにJonkのをつかえばオレオレJobQueueフレームワークを作成することは簡単です。
これで既存のJobQueueエンジンに無理やり合わせて変なコードを書かないでよくなり、
案件に応じて柔軟なフレームワークを作成してみましょう!
明日はkazeburoさんのターンです!