BackgrounDRbには、原作者が書いたわかりやすいチュートリアル"Introduction to BackgrounDRb"が存在しており、BackgrounDRbで検索するとこのページの内容を実践されている方のブログなどがヒットするのですが、残念ながらBackgrounDRb 1.0では仕様が大きく変わっており、このチュートリアルは動作しません。
そこで、BackgrounDRb 1.0で上記のチュートリアルと似たようなことを実現してみたいと思います。
イメージとしては、ボタンを押すと動画の変換処理がスタートして、状態表示ページにアクセスすると、変換処理が何%終了したかを表示する、そんなアプリケーションを作りたいのですが、動画の変換とかを本当に実装するのは時間の制約上難しいので、ここでは単に終了までに100秒かかるworkerを実装しましょう。
「スタート」を押す→処理がはじまる→処理の進捗状況がグラフ表示されるという感じのものを作りたいと思います。
構成要素に分けると、
- 1から100までを一秒に1ずつカウントアップするworker
- そのworkerをキックするページA
- そのworkerの進捗状況をJSONかRJSで返すページB
- Bを定期的に呼び出し進捗グラフを表示するAjaxなページC
退屈な順に、workerからいってみましょう!
1から100までを一秒に1ずつ数え上げるworker
良い名前が浮かびませんので、チュートリアルに倣ってFooWorkerと名付けましょう。BackgrounDRbにはworkerのジェネレータがついていますので、generateコマンドでworkerのテンプレートを生成することができます。
$ ./script/generate worker foo exists lib/workers/ create lib/workers/foo_worker.rb
では、生成されたlib/workers/foo_worker.rbを見てみましょう。
class FooWorker < BackgrounDRb::MetaWorker set_worker_name :foo_worker def create(args = nil) # this method is called, when worker is loaded for the first time end end
非常にシンプルですね。
さて、復習すると、1から100までを1秒に1ずつ数え上げるworkerを実装するのでした。
1から100までの数字を保持するのインスタンス変数を定義して、その変数のgetterを...と考えてしまうところなのですが、BackgrounDRbには、statusという概念があります。statusは、(おそらく)workerの「現状」をMiddleManに受け渡すことを想定して作られており、Rails側からはMiddleManを通して簡単にstatusにアクセスすることができます。せっかくなのでここはこのstatusを利用してみましょう。
statusに値を「登録」するには、register_statusメソッドを利用します。今回は、このregister_statusを利用してみましょう。以下のようになります。数え上げるメソッドを、count_upとしました。
lib/workers/foo_worker.rb
class FooWorker < BackgrounDRb::MetaWorker set_worker_name :foo_worker def create(args = nil) # this method is called, when worker is loaded for the first time end def count_up (1..100).each { |i| register_status(i) sleep 1 } end end
ではこれを手動で呼び出してみましょう。
前回見た手順で、backgroundrbのサーバーを起動します。
$ ./script/backgroundrb start
次に、Railsのコンソールを起動します。ここにコマンドを打ち込んで手動でworkerの機能を呼び出しましょう。
$ ./script/console Loading development environment (Rails 2.0.2) >> MiddleMan.query_all_workers => {:foo_worker=>nil, :log_worker=>nil}
FooWorkerはbackgroundrbの起動時に読み込まれ、インスタンスが存在しているようです。
>> MiddleMan.ask_work(:worker => :foo_worker, :worker_method => :count_up) => nil
これでworkerのメソッドcount_upが呼び出されたはずです。続けて、statusを取得してみてください(急いで!)。
>> MiddleMan.ask_status(:worker => :foo_worker) => 11 >> MiddleMan.ask_status(:worker => :foo_worker) => 12 >> MiddleMan.ask_status(:worker => :foo_worker) => 13
一秒ごとに、statusがカウントアップされているのがわかりますね。
しばらく待ってから実行すると、
>> MiddleMan.ask_status(:worker => :foo_worker) => 100
...こんな感じでカウントアップが終了していることがわかります。
一目瞭然ではありますが、MiddleMan.ask_workは、特定のworkerにあるメソッドの実行をお願いするメソッドです。MiddleMan.ask_statusは、workerが登録したstatusを取得するメソッドです。
これでworkerはとりあえず完成です!あとはこのworkerをRailsから呼び出せば良いわけです。開始するページはMiddleMan.ask_workを呼び出し、進捗を返すページはMiddleMan.ask_statusを呼び出せば良さそうですね。
では続きはまた次回。(中断する場合には./script/backgroundrb stopをお忘れなく)
Leave a comment