Railsのコントローラで定義したメソッドの中で、長い処理は非同期で行いたいときはありませんか?例えばユーザー登録のメール送信などは、コントローラのメソッドの中でメールが送信されるまで処理を止めるのではなく、非同期にして先に「登録が完了しました。」とページを表示させてあげる。こういうのをrailsでやるのにresqueというgemが役立ちます。
このgemのチュートリアルである下記の記事を試してみました。
Hello World Resque (Railsにresqueを導入する) | hello-world.jp.net
今回は定義したキューを実行させるための下記のコマンドを掘り下げて見ていこうと思います。
QUEUE=resque_sample rake environment resque:work
ちなみに次のように書いても実行できます。QUEUEを後ろに回しただけです。
rake environment resque:work QUEUE=resque_sample
QUEUEは環境変数で、どの種類のタスクを実行するのか決めている
QUEUE=resque_sample
はQUEUE
という環境変数を定義して、そこにresque_sampleという文字列を格納しています。その後にrakeでタスクを走らして、そのタスク内でこの環境変数の中身を使っているわけです。
参考:Linux - シェル変数と環境変数の違いをコマンドラインで確認する - Qiita
簡単な例をあげます。 ruby_script_test
とうファイルを作り、次のとおりに記述します。その後chmod 755 ruby_script_test
をコマンドラインから実行して、このファイルに実行権限を与えてあげましょう。
#!/usr/bin/env ruby
puts ENV['SAY']
そしてコンソールで次のように打ってください。環境変数の中身が出力されましたね。
$ SAY=hello
$ ./ruby_script_test
hello
rubyで記述されたファイルをrubyコマンドなしで実行できる仕組みは下記が参考になります。簡潔にまとめると、ファイルの拡張子があろうがなかろうか、1行のめシバンとよばれる#!~
の記述でどのコマンドで実行すればいいかをファイル自体に記述しているからrubyコマンドなしで実行できるわけです。
ruby - rubyで作ったプログラムをターミナルからコマンドで実行したい。 - スタック・オーバーフロー
ちなみに、QUEUE
にresque_sample
を指定していますが、これはapp/workers/hello.rb
に@queue = :resque_sample
と記述したからです。@queue = :another_task
とした場合は、QUEUE=another_task rake environment resque:work
と実行しなければなりません。
キューというのはタスクをやることリストとして管理するためのもので、それをいくつか名前をつけて用意できます。今回だと、resque_sample
やanother_task
という2種類のキューを試したわけです。QUEUE= resque_sample rake environment resque:work
とはresque_sample
というキューに登録されたタスクを消費し始めるとコマンドです。「消費し始める」が重要ですよ。このコマンドを実行していなくても、今回のチュートリアルの/helo/worldというページにアクセスすればResque.enqueue
が実行されてキューにどんどん溜まっていきます。その後にQUEUE= resque_sample rake environment resque:work
を実行すれば、溜まったタスクがどんどん実行されていくので、ページにアクセスしなくても実行されているように見えます。
実際にはRedisというKVSのDBに、「resque:queue:ワーカ名」の配列としてどんどんジョブが格納されていきます。そして実行が終わるたびに配列から要素が取り出されていきます。詳しくは下記を参考。
Resqueで色々やって、Redisに何が格納されているのか調べてみた - kitak.blog
environmentはモデルを読み込むために使う
rakeコマンドにenvironmentという引数を渡しています。これを渡すことによってタスク内でActive Recordのモデルなどを使用できるようになります。下記はrake user:regist
で実行できるタスクです。中でUserモデルを使用しています。これはtask関数でenvrionmentを渡しているからです。これを削除したらUserモデルは使えなくなってしまいます。
# lib/task/user.rake
namespace :user do
desc "ユーザーを登録するタスクです。"
task regist: :environment do
User.create(name: '太郎')
end
end
しかし、この記述がなくてもUserモデルをタスク内で使える方法があります。それが最初にあげたコマンドのrake environment
です。コマンドラインからenvironment
を渡しているのでモデルなどが使用できるようになるわけです。
参考:[rails]Rakeタスクでのtask定義の「:environment」引数について | アプレンティス プラクティス
resque:workというタスクはどこで作られる?
lib/tasks/resque.rake
というファイルを作成して、require 'resque/tasks'
という記述を書きましたよね。resque/tasks
を読み込むことによって自動で作られるみたいです。githubのlib/resuq/tasks.rbを見てみましょう。コメントにもこれをrequireしたらresqueタスクが作られると書いてありますよね。それとnamespace :resque
の中にtask :work
が定義されていることも確認できます。
# require 'resque/tasks'
# will give you the resque tasks
require 'resque/cli'
namespace :resque do
task :setup
desc "Start a Resque worker"
task :work => [ :preload, :setup ] do
warn "DEPRECATION WARNING: Rake tasks are deprecated. Use `resque work` instead"
opts = [
"-q", ENV['QUEUES'] || ENV['QUEUE'] || "*",
"-t", ENV['RESQUE_TERM_TIMEOUT'] || 4.0,
"-d", !ENV['BACKGROUND'].nil?,
"-p", ENV['PIDFILE'],
"-i", ENV['INTERVAL'] || 5
]
Resque::CLI.new([], opts).invoke(:work)
end
# 略
end