【Rails, Docker】開発環境に Sidekiq を導入する
概要
Rails で非同期処理を行う際に、キューイングシステムとして Sidekiq を使用することが多いかと思います。
今回は Sidekiq を docker-compose.yml を用いて開発環境に導入する方法を書いていきます。
環境
Gems
rails (7.0.8)
redis (5.1.0)
sidekiq (7.2.2)
RUBY VERSION
ruby 3.1.2p20
redis
Redis server v=7.2.3
概念図
この Sidekiq の話をするときに、注射器をイメージするとわかりやすいかと思います。
めっちゃ拙い絵で申し訳ないですが、Rails, Sidekiq, Redis の各立ち位置としては以下のような感じです。
- Redis...注射器の容器
- ジョブ(ActiveJob によって作成される)...注射器の中身
- Sidekiq...押し出すやつ
導入手順
Redis コンテナを作成
docker-compose.yml に redis コンテナを追加します。
version: '3.9'
services:
...
redis:
image: redis
コンテナを起動します。
❯ docker compose up
コンテナに入り、redis が起動しているか確認します。
❯ docker compose exec redis bash
# コンテナ内
❯ redis-server --version
Redis server v=7.2.3 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=844e0bcfd16d3790
redis の基本的な使い方は別記事に書いていますので参考にしてください。
必要な gem のインストールと設定を行う
Sidekiq の設定で環境変数を設定する必要があるので、一緒にdotenv-rails
もインストールしておきます。
gem 'sidekiq'
gem 'redis'
gem 'dotenv-rails'
config/application.rb で、キューイングサービスを sidekiq を使用するようにします。
config.active_job.queue_adapter = :sidekiq
次に、routes.rb に以下を追加することで、キューやジョブを UI で確認することができます。
mount Sidekiq::Web, at: '/sidekiq'
/sidekiq
に遷移してみましょう。
以下の画面が表示されるはずです。
サンプルのワーカーとジョブを作成する
class SampleJob
include Sidekiq::Worker
def perform
puts 'ジョブを実行しました!!!!!'
end
end
動作確認
rails console を起動して、以下のコマンドで、sidekiq のキューにジョブを追加することができます。
> SampleJob.perform_async
上記コマンドを5回実行したあと、/sidekiq/busy
にアクセスしてみましょう。
すると、「待機状態」が5になっています。
/sidekiq/queues/default
に遷移すると、積まれているジョブの詳細が確認できます。
次に、rails アプリケーションのコンテナに入り、以下を実行します。
> bundle exec sidekiq
すると、以下のログが流れるはずです。
[dotenv] Loaded .env
m,
`$b
.ss, $$: .,d$
`$$P,d$P' .,md$P"'
,$$$$$b/md$$$P^'
.d$$$$$$/$$$P'
$$^' `"/$$$' ____ _ _ _ _
$: ',$$: / ___|(_) __| | ___| | _(_) __ _
`b :$$ \___ \| |/ _` |/ _ \ |/ / |/ _` |
$$: ___) | | (_| | __/ <| | (_| |
$$ |____/|_|\__,_|\___|_|\_\_|\__, |
.d$$ |_|
2024-03-24T14:48:26.300Z pid=195 tid=397 INFO: Booted Rails 7.0.8 application in development environment
2024-03-24T14:48:26.301Z pid=195 tid=397 INFO: Running in ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]
2024-03-24T14:48:26.301Z pid=195 tid=397 INFO: See LICENSE and the LGPL-3.0 for licensing details.
2024-03-24T14:48:26.301Z pid=195 tid=397 INFO: Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org
2024-03-24T14:48:26.301Z pid=195 tid=397 INFO: Sidekiq 7.2.2 connecting to Redis with options {:size=>10, :pool_name=>"internal", :url=>"redis://redis:6379/0"}
2024-03-24T14:48:26.305Z pid=195 tid=397 INFO: Sidekiq 7.2.2 connecting to Redis with options {:size=>5, :pool_name=>"default", :url=>"redis://redis:6379/0"}
2024-03-24T14:48:26.305Z pid=195 tid=397 INFO: Starting processing, hit Ctrl-C to stop
2024-03-24T14:48:26.310Z pid=195 tid=aiv class=SampleJob jid=31121d52b7b896591bd432e6 INFO: start
2024-03-24T14:48:26.327Z pid=195 tid=ai3 class=SampleJob jid=b5e8c8e04f8118472b63c5b3 INFO: start
2024-03-24T14:48:26.312Z pid=195 tid=ajf class=SampleJob jid=cc379d9beb695b3ce7b0839c INFO: start
2024-03-24T14:48:26.411Z pid=195 tid=ain class=SampleJob jid=216378612d37c5e105898656 INFO: start
2024-03-24T14:48:26.312Z pid=195 tid=ajz class=SampleJob jid=38a24d1140ec91d1ca7b2931 INFO: start
ジョブを実行しました!!!!!
2024-03-24T14:48:26.602Z pid=195 tid=ai3 class=SampleJob jid=b5e8c8e04f8118472b63c5b3 elapsed=0.274 INFO: done
ジョブを実行しました!!!!!
2024-03-24T14:48:26.604Z pid=195 tid=ajf class=SampleJob jid=cc379d9beb695b3ce7b0839c elapsed=0.292 INFO: done
ジョブを実行しました!!!!!
2024-03-24T14:48:26.604Z pid=195 tid=aiv class=SampleJob jid=31121d52b7b896591bd432e6 elapsed=0.294 INFO: done
ジョブを実行しました!!!!!
2024-03-24T14:48:26.610Z pid=195 tid=ain class=SampleJob jid=216378612d37c5e105898656 elapsed=0.199 INFO: done
ジョブを実行しました!!!!!
2024-03-24T14:48:26.611Z pid=195 tid=ajz class=SampleJob jid=38a24d1140ec91d1ca7b2931 elapsed=0.299 INFO: done
「ジョブを実行しました!!!!!」が5回出力されています。
もう一度 /sidekiq/busy
を確認すると、「待機状態」が0になり、
完了が5件増えている事がわかります。
サンプルのメーラーを作成して実行してみる
メールを送信すると仮定したクラスを作成します。
実際にメールを送信するときは ActionMailer を使うことが多いと思いますが、
今回は簡易的に ActiveJob を使用して非同期処理を実行します。
class SampleJob
include Sidekiq::Worker
def perform
SampleMailJob.perform_later
puts 'ジョブを実行しました!!!!!'
end
end
class SampleMailJob < ApplicationJob
def perform
sleep_time = 5
sleep sleep_time
puts "メールを送信しました!#{sleep_time}秒かかりました"
end
end
上記の SampleMailJob.perform_later
の部分が、メール送信でいうところの、
deliver_later
メソッドで、メール送信処理を非同期的に実行できます。
ActionMaler | ActveJob | |
---|---|---|
非同期で処理を実行 | deliver_later | perform_later |
同実行に処理を実行 | deliver_now | perform_now |
再度、rails console から以下を実行してみます。
> SampleJob.perform_async
すると、Sidekiq のログから、最初にワーカーの処理が終了し、
その後にメール送信処理が実行されていることがわかります。
2024-03-24T15:14:35.277Z pid=195 tid=buj class=SampleJob jid=2a306f9393cdc21d0800b7ff INFO: start
Enqueued SampleMailJob (Job ID: 1a0156df-b900-4b04-86f2-b17fb6532890) to Sidekiq(default)
2024-03-24T15:14:35.316Z pid=195 tid=bob class=SampleMailJob jid=dbc901f10238ff28b84d2e6f INFO: start
ジョブを実行しました!!!!!
2024-03-24T15:14:35.317Z pid=195 tid=buj class=SampleJob jid=2a306f9393cdc21d0800b7ff elapsed=0.04 INFO: done
Performing SampleMailJob (Job ID: 1a0156df-b900-4b04-86f2-b17fb6532890) from Sidekiq(default) enqueued at 2024-03-24T15:14:35Z
メールを送信しました!5秒かかりました
Performed SampleMailJob (Job ID: 1a0156df-b900-4b04-86f2-b17fb6532890) from Sidekiq(default) in 5005.83ms
2024-03-24T15:14:40.349Z pid=195 tid=bob class=SampleMailJob jid=dbc901f10238ff28b84d2e6f elapsed=5.033 INFO: done
まとめ
今回は Sidekiq の開発環境への導入手順について書きました。
本番では 分離と独立性の観点から、Sidekiq は別コンテナで動かすことが多いですが、それはまた別記事でやってみようと思います。
参考:
Discussion