Rails で非同期処理(バックグラウンドジョブ)を実現するライブラリの Resque を使ってみた.
非同期処理のハンドリングを全て Rails で扱えるのが利点で,バックエンドは Redis で動く.さらに sinatra ベースの Resque 管理画面もデフォルトで入ってて,ジョブの状況を確認できるのが結構イケてる感じ.しかも GitHub が作ってるっていうのが驚き.
Resque の使い所としては,README.md を見るとすぐにレスポンスを返せない not always fast
な処理もあるから,そういうものに Resque が使えると書いてある.例として以下の7種類が挙げられてた.まぁ他にも,画像変換をしたり,帳票を作成したりするのもそうだし,そういうちょっと重めの処理をするときにユーザのアクションを止めないで裏側で処理するときに使うライブラリって感じ.ただまぁ,README.md だけみてもすぐにコードを書ける感じじゃなくて,いろいろサンプルを探して読んでみる必要はあったけど,それでもとてもシンプルに作られていた.
- Warming caches
- Counting disk usage
- Building tarballs
- Firing off web hooks
- Creating events in the db and pre-caching them
- Building graphs
- Deleting users
ちなみに,Resque の拡張機能で Resque-scheduler っていうのもあって,これは Resque で制御する非同期処理を計画的に非同期で実行するためのもので,大きく2種類の計画方法がある.
- Delayed Jobs
- 1時間後に非同期処理を1回だけ実行,みたいな使い方をする (Linux で言う
at
)
- 1時間後に非同期処理を1回だけ実行,みたいな使い方をする (Linux で言う
- Scheduled Jobs (Recurring Jobs)
- 1時間に1回非同期処理を実行,みたいなスケジュールとして使う (Linux で言う
crontab
)
- 1時間に1回非同期処理を実行,みたいなスケジュールとして使う (Linux で言う
非同期アプリケーションを作ってみる
Rails アプリケーションを作る.アプリケーショ名は適当に job-resque
にしておく.
$ rails new job-resque
./Gemfile に gem を追加する.
gem "resque"
Resque 用の rake を作成する.
$ rails g task resque
作成した ./lib/tasks/resque.rake でタスクを読み込む.
require 'resque/tasks'
./config/routes.rb に Resque 用の定義を追加する.
require 'resque/server' Rails.application.routes.draw do get 'users/:name', :to => 'users#show' mount Resque::Server.new, at: "/resque" end
サンプルとして users コントローラーを追加する.
$ rails g controller users
追加した ./app/controllers/users_controller.rb に show アクションを書く.この Resque.enqueue(Mylogger, params[:name])
というのが,Resque に非同期処理をリクエストするところ.
class UsersController < ApplicationController def show Resque.enqueue(Mylogger, params[:name]) render :text => params[:name] end end
非同期処理の Worker として mylogger.rb を追加する.
$ mkdir ./app/workers $ vim ./app/workers/mylogger.rb
追加した ./app/workers/mylogger.rb はこんな感じ.サンプルなので何でも良くて,単純にリクエストパラメータをログに書き出すだけの処理.
class Mylogger @queue = :default def self.perform(name) path = File.expand_path("log/users.log", Rails.root) File.open(path, 'a') do |f| f.puts "User: #{name}" end end end
これだけでOK.
非同期アプリケーションを起動してみる
Redis を起動して,Rails アプリケーションを起動して http://localhost:3000/users/kakakakakku
にアクセスすると,View としては kakakakakku
が表示されるだけだが,既にバックエンドジョブが追加されている.ちなみにこのとき Redis が起動されてないと,以下のエラーが出るので,redis-server
を忘れないように.
Redis::CannotConnectError - Error connecting to Redis on 127.0.0.1:6379 (ECONNREFUSED):
Worker を起動して非同期処理をさせる
今の状態だと,非同期処理のリクエストが Redis に入っていくだけなので,Worker を起動して,非同期処理をさせてみる.
今回の非同期処理は,/users/xxx
で指定した xxx
をログに書き出すだけだけど,ターミナルを2枚上げて,1枚は tail -f log/users.log
でログを監視する.もう1枚の方で Worker を起動する.
QUEUE=default rake environment resque:work
そうするとこんなログが書き出されるので,これで非同期処理が実現できていることがわかる.この状態で他の xxx
でどんどんURLを叩いていけば,同様にログが書き出される.
User: kakakakakku
Resque 管理画面にアクセスしてみる
http://localhost:3000/resque/
にアクセスすると,Resque の管理画面にアクセスできる.動作確認のため,まずは Worker を止めておく.
デフォルトの状態だと,Jobs も Workers も0になっている.
ここで http://localhost:3000/users/kakakakakku
にアクセスして,管理画面を更新すると,Jobs が1になっている.
Queues タブを見てみると,ちゃんと Class: Mylogger, Args: ["kakakakakku"]
と非同期処理の情報が表示されている.
ここで Worker を再度立ち上げて非同期処理を流した後にアクセスしてみると,非同期処理が既に行われているので,Jobs は0になって,Workers が1になっている.
まとめ
Resque を使えば Rails でお手軽に非同期処理が実現できる!素晴らしい!
関連エントリー
Background Jobs with Resque - Jumpstart Lab Curriculum
GitHub製Resqueを使用したRubyでのバックグラウンド処理(バッチ処理) - Masatomo Nakano Blog
resqueとRails - Masatomo Nakano Blog
RailsでResque使い始めた - Masatomo Nakano Blog
Hello World Resque (Railsにresqueを導入する) - Qiita