【Ruby on Rails】sidekiqの導入手順(ローカル、Heroku、AWS EC2、Docker、Capistrano)


redisを準備する

sidekiqを使う為にredisが必要です。

redisインストール(Mac OS)

brew install redis

redis起動

brew services start redis

docker-composeを使う場合

docker-compose.yml
  redis:
    image: redis:latest
    volumes:
      - redis:/data
    ports:
      - 6379:6379

アプリケーションにsidekiqを導入する

Gemfile
gem 'sidekiq'
config/application.rb
config.active_job.queue_adapter = :sidekiq

sidekiqを起動する

sidekiq -q default -q mailers

もしくは

config/sidekiq.yml
:concurrency: 25
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
  - default
  - mailers
  - active_storage_analysis
  - active_storage_purge
:daemon: true
sidekiq -C config/sidekiq.yml

サンプル

アプリケーションには Message というモデルがあり、そのモデルが content と sidekiq_executed_time カラムを持ちます。

例えば、SampleJobを作るとします。

rails g job SampleJob

生成したJobは全ての Message の sidekiq_executed_time を現時点に更新します。

app/jobs/sample_job.rb
class SampleJob < ApplicationJob
  queue_as :default

  def perform(*args)
    sleep(1)
    Message.find_each do |message|
      message.update(sidekiq_executed_time: DateTime.current)
    end
  end
end

コントローラーでは、新規 Message が作成された時に、Jobを非同期実行します。

app/controllers/messages_controller.rb
def create
  @message = Message.new(message_params)
  if @message.save
    redirect_to messages_path, notice: 'Message was successfully created.'
    SampleJob.perform_later
##### 省略 #####

実際に新規 Message を作成したら、最初は sidekiq_executed_time がなかったが、数秒後ページをリロードすると値があって、Jobがちゃんと実行されたことが分かります。

sidekiqジョブの管理画面

config/routes.rb
require 'sidekiq/web'

Rails.application.routes.draw do
  mount Sidekiq::Web => '/sidekiq'

  # 認証が必要の場合
  Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
    [user, password] == [ENV['SIDEKIQ_USERNAME'], ENV['SIDEKIQ_PASSWORD']]
  end
##### 省略 #####

そして、localhost:3000/sidekiqにアクセスすると管理画面が現れるはずです。

Flush Sidekiq's Redis DB

Railsコンソールで
Sidekiq.redis { |r| puts r.flushall }

Herokuで使う

Heroku redisの追加

heroku addons:create heroku-redis:hobby-dev

Heroku Redis との接続設定

config/initializes/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379') }
end

Sidekiq.configure_client do |config|
  config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379')}
end

Procfile の作成

web: bin/rails server -p $PORT -e $RAILS_ENV
worker: bundle exec sidekiq -c 3 -q default -q mailers

デプロイの後、worker dyno を作る

heroku ps:scale web=1 worker=1

AWS EC2で使う

AWS ElastiCache との接続設定

config/initializes/sidekiq.rb
Sidekiq.configure_server do |config|
  if Rails.env.production?
    redis_conn = proc {
      Redis.new(host: ENV['AWS_REDIS_ENDPOINT'], port: 6379, db: 2)
    }
    config.redis = ConnectionPool.new(size: 27, &redis_conn)
  else
    config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379') }
  end
end

Sidekiq.configure_client do |config|
  if Rails.env.production?
    redis_conn = proc {
      Redis.new(host: ENV['AWS_REDIS_ENDPOINT'], port: 6379, db: 2)
    }
    config.redis = ConnectionPool.new(size: 27, &redis_conn)
  else
    config.redis = { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379') }
  end
end

capistrano-sidekiqの設定

Gemfile
gem 'capistrano-sidekiq', require: false, group: :development
Capfile
require 'capistrano/sidekiq'
config/deploy.rb
set :rbenv_map_bins, fetch(:rbenv_map_bins).to_a.concat(%w(rake gem bundle ruby rails puma pumactl sidekiq sidekiqctl))
set :init_system, :systemd

sidekiqがうまく動かない場合

cap production sidekiq:install

サーバーにアクセスして、sidekiq-production.serviceを修正する

/home/USER/.config/systemd/user/sidekiq-production.service
ExecStart=/home/deploy/.rbenv/shims/bundle exec sidekiq -e production -C config/sidekiq.yml

上の「/home/deploy/.rbenv/shims/bundle」がwhich bundle で確認できたものです。

修正が終わってから、以下のコマンドを実行する

sudo systemctl daemon-reload && systemctl --user reenable sidekiq-production.service && systemctl --user stop sidekiq-production.service && systemctl --user start sidekiq-production.service && sleep 3 && systemctl --user status sidekiq-production.service

sidekiqを再起動する

cap production sidekiq:restart

>>> サンプルアプリケーション