いくつかのジョブを一定期間バッファリングしておき、実行時に同じようなメソッドがあったら、別のメソッドをよびだす、という処理をするgemを書きました。
想定シナリオ
たとえばブログ的なサービスを運営していたとして、各記事にコメントがついたときにメール通知をしたいとします。コメント毎にメール通知していると人気のあるユーザーには毎回大量の同じようなメールがとんでしまいます。一定時間(例えば2〜3分)バッファリングしておき、同じような内容が複数存在する時には別のメソッドで受け取って本文中に展開して一通で送る、といった処理を実現するためのモジュールです
例えば下記のような処理があった場合
@article = Article.create(:user => @user,:text => "my blog article here")
c = @article.comments.create(:user => @jon, :text => "i love this article!")
@user.notify(c)
メソッドの実行をバッファしておくことにより、一定時間後に別のmerge_を頭につけたメソッドが配列になった対象オブジェクトとともに該当レシーバに送られます
c1 = @article.comments.create(:user => @jon, :text => "i love this article!")
c2 = @article.comments.create(:user => @ken, :text => "i hate this article!")
@user.buffer.notify(c1)
@user.buffer.notify(c2)
# ここで一定期間がたつと、notifyメソッドの変わりにmerge_notifyメソッドがよばれる。
@user.merge_notify([c1,c2]) # <- これと同等の処理が実行される
インストール
gem 'buffered_job'
そしてbundle install
。または
$ gem install buffered_job
前準備
テーブルの作成をします
$ (bundle exec) rails generate buffered_job
$ (bundle exec) rake db:migrate
依存関係
ジョブの実行
delayed_job経由で行います。 delayed_job_active_recordを参考に必要なテーブルなどセットアップしたのちにワーカーを動かしてください
$ (bundle exec) rake jobs:work
使い方
全てのActiveRecordオブジェクトはbuffer
メソッドを持ちます。bufferをレシーバーとメソッドの間に置いてください。
@user.buffer.post_to_twitter(@article1)
@user.buffer.post_to_twitter(@aritcle2)
もしバッファリング期間後に同じレーシーバに対して、同じメソッドが複数回よばれていたら、引数を配列にまとめた上でmerge_をメソッド名の頭につけたメソッドがよびだされます。なので、この例では下記のメソッドをUserモデルに実装しておくひつようがあります
def merge_post_to_twitter(articles)
# ..
end
現在の制限
バッファするメソッドに渡す引数オブジェクトは一つに限定してます
Configuration
デフォルトのバッファ時間は3分です。変更するには下記
BufferedJob.delay_time = 30.seconds