【Rails】Sidekiq用コンテナで非同期処理を蹴っ飛ばす

2024/02/01に公開

dockerコンテナでホストしたrailsでの非同期処理実行環境を整えるまでの備忘録です。
「一つのコンテナ、一つの責務」がdockerの基本なので、下記をそれぞれ別立てで揃えていきます。

  • rails用コンテナ
  • sidekiq実行用コンテナ
  • redis用コンテナ (sidekiqのキューイングに使う )

一般的に推奨するのは、1つのサービスごとにコンテナを使い、懸念事項の領域を分ける方法です。

https://docs.docker.jp/v19.03/config/container/multi-service_container.html

コンテナ作成

docker-compose.yml

compose.ymlで必要なコンテナを定義します。
app_containerとsidekiq_containerはbuild時に処理が必要なのでDockerfileに切り出します。
ポイントは一点で、sidekiqを実行するコンテナはgemやconfig/sidekiq.ymlを必要とするのでrailsを実行するコンテナをマウントする必要があります。
volumes: - .:/workspaceで定義app_containerとsidekiq_containerが同じディレクトリをマウントすることで実現されています。

docker-composeyml
version: '3'
services:
  app:
    container_name: app_container
    build:
      context: ./.docker/app/Dockerfile
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DEV_DATABASE: ${POSTGRES_DEV_DATABASE}
      POSTGRES_TEST_DATABASE: ${POSTGRES_TEST_DATABASE}
      POSTGRES_PRO_DATABASE: ${POSTGRES_PRO_DATABASE}
    volumes:
      - .:/workspace
    tty: true
    stdin_open: true
    ports:
      - 3000:3000

  sidekiq:
    container_name: sidekiq_container
    build:
      context: ./.docker/sidekiq/Dockerfile
    volumes:
      - .:/workspace
    depends_on:
      - redis

  redis:
    container_name: redis_container
    image: redis:7.0
    env_file: .env
    command: redis-server --appendonly yes
    ports:
      - 6379:6379

  db:
    container_name: db_container
    image: postgres
    ports:
      - 5432:5432
    volumes:
      - rails_db_volume:/var/lib/postgresql/data
    environment:
      POSTGRES_ALLOW_EMPTY_PASSWORD: "yes"
      POSTGRES_ROOT_PASSWORD: ${POSTGRES_ROOT_PASSWORD}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DEV_DATABASE: ${POSTGRES_DEV_DATABASE}

volumes:
  rails_db_volume:

Dockerfile

次に、Dockerfileを定義します。
今回はsidekiqコンテナが記事のスコープなので、app_containerのDockerfileに関する説明は行いません。

Dockerfileでは、rubyイメージのbuildと、bundle installに必要なプロセスを定義しています。
最終行で、独自の/config/sidekiq.ymlで書いた設定を読み込んでsidekiqを実行するように定義しています。

/.docker/app/Dockerfile
FROM ruby:3.2.2-alpine3.18

RUN apk update -qq && apk add gcompat libpq-dev nodejs vim g++ make

WORKDIR /workspace

COPY ../ ../

RUN bundle install

CMD [ "bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"  ]

rails側の設定

Gemfile

sidekiqredisのインストールが必要です。

Gemfile
gem "redis", "~> 5.0"

gem 'sidekiq', '~> 7.2'

sidekiq設定

使用するsidekiqの設定を行います。
concurrencyでキューサービスに保持できるjobの数を設定。
queueaで使用するキューの種類を設定。

/config/sidekiq.yml
:verbose: false
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:concurrency: 10
:queues:
  - default
  - mailers

redis設定

sidekiqが使用するredisサーバの設定を行います。
url: 'redis://redis:6379/0'でhostとportを指定することで、コンテナとして定義したredisを使用するように定義しています。

/config/initializes/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { url: 'redis://redis:6379/0' }
end

Sidekiq.configure_client do |config|
  config.redis = { url: 'redis://redis:6379/0' }
end

route定義

sidekiqコンソールを確認するためのパスを定義します。

/config/route.rb
Rails.application.routes.draw do
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"

  require 'sidekiq/web'
  mount Sidekiq::Web, at: "/sidekiq"

  # other paths
end

http://localhost:3000/sidekiq/

job作成

job_itemsテーブルにcreate処理を行うjobを作成します。

terminal
% rails g job example_job
/app/job/example_job.rb
class ExampleJob < ApplicationJob
  queue_as :default

  def perform(*args)
    JobItem.create!(name: 'name01', user_id: "1")
  end
end

実行↓

terminal
% rails c

[1] pry(main)> ExampleJob.perform_later
pid=28 tid=2qo INFO: Sidekiq 7.2.0 connecting to Redis with options {:size=>10, :pool_name=>"internal", :url=>"redis://redis:6379/0"}
Enqueued ExampleJob (Job ID: 0f3da019-b58b-4eae-9bd8-29ef7c12a0c0) to Sidekiq(default)
=> #<ExampleJob:0x00007fae51456120
 @arguments=[],
 @exception_executions={},
 @executions=0,
 @job_id="0f3da019-b58b-4eae-9bd8-29ef7c12a0c0",
 @priority=nil,
 @provider_job_id="04cf9d1e5cde6a21aa18d42d",
 @queue_name="default",
 @successfully_enqueued=true,
 @timezone="UTC">

[2] pry(main)> JobItem.all
  JobItem Load (1.9ms)  SELECT "job_items".* FROM "job_items"
=> [#<JobItem:0x00007fae51713fc0
  id: 7,
  name: "name01",
  user_id: 1,
  created_at: Wed, 31 Jan 2024 23:24:50.961593000 UTC +00:00,
  updated_at: Wed, 31 Jan 2024 23:24:50.961593000 UTC +00:00>]

jobの実行でcreateが成功しているので、sidekiqコンソールを確認してみます。

sidekiqを通してjobの実行に成功しています。
メトリクスのページに飛ぶと、アプリケーション内で管理されるjobの実行状況を一覧で確認できたりもします。


今回は以上になります。
ここまで読んでいただき、ありがとうございました。

Discussion