はじめに
この記事では、Dockerを使用してRails、Sidekiq、Redisをセットアップし、指定した時間にジョブを実行する方法を紹介する。今回は、ユーザーにリマインダーメールを送信する機能を例とする。
Sidekiqとは
SidekiqはRubyのバックグラウンドジョブ処理ライブラリで、非同期処理を行うために使用される。Redisをバックエンドとして作成したジョブを管理する。
非同期処理とは
プログラムが複数のタスクを並行して実行すること。重い処理や時間のかかる処理をバックグラウンドで行うことでパフォーマンスを向上させることができる。
メールの送信やデータのバッチ処理など、時間のかかるタスクを非同期に行うことが一般的。
DockerとDocker Composeの設定
まず、DockerとDocker Composeを使用して、Rails、MySQL、Redis、Sidekiqの各サービスをセットアップをする。以下のDockerfileとdocker-compose.ymlをプロジェクトのルートディレクトリに作成する。
FROM ruby:3.1
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - && \
apt-get install -y nodejs
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN mkdir /VehicleMinders
WORKDIR /VehicleMinders
COPY Gemfile /VehicleMinders/Gemfile
COPY Gemfile.lock /VehicleMinders/Gemfile.lock
RUN bundle install
COPY . /VehicleMinders
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
version: '3'
services:
db:
platform: linux/amd64
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
ports:
- '3306:3306'
command: --default-authentication-plugin=mysql_native_password
volumes:
- mysql-data:/var/lib/mysql
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app
ports:
- "3000:3000"
depends_on:
- db
- redis
stdin_open: true
tty: true
sidekiq:
build: .
command: bundle exec sidekiq
volumes:
- .:/app
depends_on:
- db
- redis
redis:
image: redis
volumes:
mysql-data:
driver: local
Sidekiqの設定
Sidekiqを設定する。Gemfileにgem 'sidekiq'
を追加し、bundle install
を実行する。
gem 'sidekiq'
Sidekiqのダッシュボード機能を利用できるように、routes.rbに以下のコードを追加する。
http://localhost:3000/sidekiq
にアクセスすることで実行中のジョブや実行待ちのジョブを確認することができる。
Rails.application.routes.draw do
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
end
Sidekiqの設定ファイルsidekiq.rbを作成する。このファイルでは、SidekiqがRedisサーバーに接続するための設定を行う。
redis_config = { url: 'redis://redis:6379/0' }
Sidekiq.configure_server do |config|
config.redis = redis_config
end
Sidekiq.configure_client do |config|
config.redis = redis_config
end
メール送信機能の作成
メールを送信するためのUserMailerを作成する。
class UserMailer < ApplicationMailer
def reminder_email(user)
@user = notification.user
mail(to: @user.email, subject: 'Your reminder')
end
end
メール送信ジョブの作成
指定した時間にメールを送信するジョブを作成する。app/workers
ディレクトリに作成する。
ジョブは特定のタスクを実行するためのクラスで、Sidekiq::Worker
モジュールをinclude
し、perform
メソッドを定義する。perform
メソッドは、ジョブが実行されるときに呼び出される。
class ReminderMailerWorker
include Sidekiq::Worker
def perform(notification_id)
notification = Notification.find(notification_id)
UserMailer.reminder_email(notification).deliver_now
end
end
リマインダーのスケジューリング
リマインダーをスケジュールする。今回は、Notificationモデルにafter_create
とafter_update
のコールバックを追加し、リマインダーメールの送信をスケジュールする。
ジョブをキューに追加するには、perform_async
メソッドを使用する。このメソッドは、ジョブをRedisに保存し、その後バックグラウンドで実行される。
下記ではperform_at
メソッドを使用して、第一引数にperform
メソッドを実行する時間を指定している。
class Notification < ApplicationRecord
belongs_to :user
after_save :schedule_reminder_mailer, if: -> { self.datetime.present? }
private
def schedule_reminder_mailer
ReminderMailerWorker.perform_at(self.datetime, self.id)
end
end
まとめ
今回はSidekiqを使って指定した時間にジョブを実行する方法について紹介した。
sidekiq-cronというgemもあり、こちらは定期的に実行する必要があるジョブを管理することができるよう。