Gearman::Worker#register_functionで登録するfunctionを、ちょっといい感じにしてみた
今日は、Gearman workerのmanager(workerプロセスいっぱい作ったり、管理したりするようなひと)を作っていました。ところで、Gearman::Workerを使っている場合、Gearmanのworkerは、こんな風に登録します。
use Gearman::Worker; my $worker = Gearman::Worker->new; $worker->job_servers('127.0.0.1'); $worker->register_function('funtion name' => sub { my $job = shift; # ... do something ... });
しかし、このように普通に登録してしまうと、Gearman::Jobのインスタンスひとつがわたってくる関数を登録するしかなくて、階層的にfunctionを構成することが難しい。僕としては、普通のクラス階層があって、それらクラスの、たとえばworkメソッドがworker functionの実装になる、というようなことがしたいわけです。
つまり、以下のようなMyApp::Worker::**という、MyApp::Workerを継承した、それぞれのworkメソッドでworker functionを実装したクラスがあったとして、
- MyApp::Worker
- MyApp::Worker::Foo
- MyApp::Worker::Bar
- MyApp::Worker::Baz
それらのworkメソッドをworker functionとしてGearman::Workerでregister_functionするという感じ。
そこで、今回書いたworker managerでは、以下のようにしてひとつdispatcherを挟むようにしました。
worker managerのコード中、functionを登録するところ抜粋
# $self->worker_functionsは、上述のようなworker functionの実装クラス名のリストを返す # 上述の例だと、MyApp::Worker::(Foo|Bar|Baz)のリスト for my $worker_function (@{$self->worker_functions}) { $worker->register_function( $worker_function, MyApp::Gearman::Dispatcher->can('dispatch'), ) }
dispatcher
package MyApp::Gearman::Dispatcher; use strict; use warnings; use UNIVERSAL::require; sub dispatch { my $job = shift; my $worker_class = $job->{func}; $worker_class->require or die $@; $worker_class->new->work($job); } !!1;
こんな感じでdispatcherを挟んでおけば、worker functionを普通のクラスとして、以下のような感じで書ける。
package MyApp::Worker::Foo; use stirct; use warnings; use base qw(MyApp::Worker); sub work { my ($self, $job) = @_; # ... do something ... } !!1;
普通のクラス階層の中でfunctionが実装できるので、共通の処理をまとめたり、また、設定ファイルにわかりやすくまとめておいて、worker managerでいっぺんにregister_functionしたりということがしやすくなっていいんじゃないかなーと思っています。