書く契機
最近何かと使っているdelayed_jobについて改めてまとめることにした。"ちょっと高級"な機能についてもちょっと書いてみた。
delayed_jobとは?
delayed_jobとはバックグラウンドで非同期処理をしてくれるrailsのgemの一種。
ちょ、"非同期処理"とは?
簡単に言ってしまえば時間のかかる処理を、通常の処理とは別に、「あとで処理しますよリスト」に登録すること。要はあるタスクを実行している間に他のタスクを実行できる、ということ。逆は"同期処理"とよばれ、あるタスクが実行されている間、他のタスクはできない。
- 時間のかかる処理の例: メール送信・ファイルのダウンロード・アップロードなど
一度に複数の処理ができて、便利の思える非同期処理。しかしデメリットも当然あり、同時に処理されるので、下手をすればデータベースの整合性が取れなくなってしまうから要注意。
使い方(基礎)
インストール自体は色々なところにのってあるので、ここでは割愛。主にその使い方について書きます。
ワーカーの起動
以下のコマンドで起動する。"バックグラウンド"と言ってるのはこれ。
bundle exec rake jobs:work
基本的な使い方
もっとも一般的な使い方を紹介する。
Class.method(hoge)
という処理を非同期で実行したい(世間ではこれを"キューに入れる"、や、"enqueueする"などと表現する)場合は、クラスとメソッドの間にdelayを挟むだけで良い。
Class.delay.method(hoge)
何が起こるの?
delayを挟んで実際にメソッドが呼び出されたときに何が起こるのかを順を追って説明する。
- methodが呼ばれると、次に行われる処理がデータベース内のdelayed_jobsテーブルに格納される(特にhandlerというカラムに着目!)。実際に処理はまだされない。
- delayed_jobsが起動されていれば、delayed_jobsテーブル内の「実行可能」なタスクがどんどん吐き出されて、順に処理されていく(これをdequeueという)。(起動してなかったらテーブルに溜まっていくだけ。考え方はまさにキューそのもの。)
使い方(発展)
delayed_jobsのその他属性
さて、ここまでdelayed_jobsのもっとも基本的な部分について話したので、少々発展の話をば。
delayed_jobsテーブルの属性一覧を見ると、handler以外にたくさんの選択肢があるのがわかる。そのいくつかを解説していく。
- run_at: 実際にdequeueする時間を指定するためのカラム。
- queue: jobの振り分け用カラム。決まった書き方がないみたいです(<=オススメの書き方あれば誰か教えて欲しいです)。
- priority: dequeueする順番、優先順位のカラム。番号の小さいものから優先的に処理される。
- last_error: 処理が失敗した場合、そのjobは吐き出されないでそのままdelayed_jobsの中にとどまる。その際エラーメッセージはここに格納される。
- failed_at: エラーだったときにそのエラーの起こった時刻のカラム。
実際の使い方
基本的には、delayのうしろに引数として渡せば良い。以下、そのいくつかの例。
Class.delay(run_at: 3.hours.from_now, queue: 'hogehoge').method(hoge)
# メソッドが実行されてから3時間後に処理される / jobの名前はhogehoge
Class1.delay(priority: 10).method1
Class2.delay(priority: 1).method2
# 両方テーブル内に存在する場合後者の方が優先的に処理される
delayed_jobsテーブルのレコードをいじる
普段私たちは直接delayed_jobsテーブル内のレコードを書き換えたりするのはあまりしない。それでもいじりたい人もいると思うので、一応紹介。基本的には
Delayed::Job.where(queue: 'hogehoge')
Delayed::Job.find_by(run_at: Time.now - 3.hours)
などとDelayed::Jobをクラスとして扱えば良い。