[Ruby on Rails]Active Job、Sidekiqで非同期に
初めに
筆者は未経験からweb系エンジニアを目指しており、技術面接の対策として、Rails開発者が採用面接で聞かれる想定Q&A 53問(翻訳)を参考にしている。
問題の中で、聞いたことがあっても手元で動かしたことがない機能があり、今回はその1つのActive Jobについて、実際にコードを書きながら、理解を深めていく。
前提
Active Job
ジョブの処理をバックグラウンドで、非同期で実行できる機能のことをいう。主に重たい処理やリアルタイム性を伴わない処理に用いられるとのこと。
Ex.
- メールの送信
- 画像の処理
- データを集計してCSVに落とす等
Job
コンピューターがする仕事の単位。タスクのようなもの
Queue(キュー)
最も基本的なデータ構造の一つで、要素を入ってきた順に一列に並べ、先に入れた要素から順に取り出すという規則で出し入れを行う、タスクの入れ物のようなもの。
順番を待つ人の行列と同じ仕組みであるため「待ち行列」とも訳される。
アダプタ
Active Jobにはキューイングバックエンドに接続するためのアダプタが用意されている。
- async•••デフォルト。プロセスを再起動した時に、登録したジョブがなくなる
- Sidekiq•••アダプタの1つ。Redisを必要としており、Redisはコンピューターから直接アクセスできるメモリ上で動作するため、高速処理が可能
実装
今回はTaskモデルを作成しアダプタはSidekiqにて、実装していく。
1.ジョブクラスの作成
bin/rails g job task
Running via Spring preloader in process 36345
invoke test_unit
create test/jobs/task_job_test.rb
create app/jobs/task_job.rb
2. app/jobs/task_job.rbにて、jobを追加
class TaskJob < ApplicationJob queue_as :default def perform(title) Task.create!(title: title) end end
perform
•••非同期処理時に呼ばれるメソッドであり、ジョブで実行したい処理を実装する
3.キューイングバックエンドの設定
- gem sidekiq の追加。bundle install
gem 'sidekiq'
config/application.rb
でアダプタをSidekiqに指定
... module ActiveJobTodo class Application < Rails::Application config.load_defaults 6.0 config.active_job.queue_adapter = :sidekiq # 追加 end end
4.Redis環境の構築
- dockerを使用して、redis環境をpullする
% docker pull redis Using default tag: latest latest: Pulling from library/redis 1fe172e4850f: Pull complete 6fbcd347bf99: Pull complete ...
- redis環境を立ち上げる
% docker run -p 6379:6379 redis ... 1:M 25 Apr 2022 03:46:25.214 # Server initialized 1:M 25 Apr 2022 03:46:25.214 * Ready to accept connections
5.ジョブをキューへ追加する(コンソール)
irb(main):001:0> TaskJob.perform_later(title: "ブログを作成") Enqueued TaskJob (Job ID: b1095411-52eb-4c2e-bcf7-5dd135aff3cd) to Sidekiq(default) with arguments: {:title=>"ブログを作成"} ...
perform_later
•••バックエンドキューにジョブを追加する。
6.Sidekiqを起動して、ジョブを実行させる
% bundle exec sidekiq m, `$b .ss, $$: .,d$ `$$P,d$P' .,md$P"' ,$$$$$b/md$$$P^' .d$$$$$$/$$$P' $$^' `"/$$$' ____ _ _ _ _ $: ,$$: / ___|(_) __| | ___| | _(_) __ _ `b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` | $$: ___) | | (_| | __/ <| | (_| | $$ |____/|_|\__,_|\___|_|\_\_|\__, | .d$$ |_| ...
7.ジョブが実行されたことが確認できる
irb(main):002:0> Task.last Task Load (0.3ms) SELECT "tasks".* FROM "tasks" ORDER BY "tasks"."id" DESC LIMIT ? [["LIMIT", 1]] => #<Task id: 1, title: "{:title=>\"ブログを作成\"}", body: nil, created_at: "2022-04-25 04:13:42", updated_at: "2022-04-25 04:13:42">