sidekiq + redisの構築(Rails 4系)
非同期処理を取り入れる提案をして、採用されたので構築していました。アウトプットとして何回かに分けて記事を書いていきます。
前提環境
前提環境の背景を話すと、Rails 5系にアップデートできていないプロジェクトです。テストは随時入れていますので、工数が取れればアップデートは出来ますが今のところ予定はないです。
サーバ構成はこんな感じ AWS EC2( Application Server Rails) <=> AWS EC2(Batch Server Rails, sidekiq(worker), Batch(cron)) <=> Aws ElastiCache(Redis, クラスターモード無し)
Rails 4.2系でもActive Jobがあり、retry
機能が想定しているエラーを迂回できそうになかったので、worker
クラスを実装して進めています。ActiveJobを利用するとRailsがadapterをラップしていることによるメリットもあり、ユースケースを満たせれば,テストコードも楽に書けるようになり採用は出来たと思います。
まずredisのインストールは、この記事ではローカル上にインストールします。(Dockerはまた別の機会に書きます) Hometbrewを利用してインストールします。
redis
brew install redis redis-server `/usr/local/etc/redis.conf`が保存されている。
続いてAppに実装
# Gemfile gem 'sidekiq'
bundle install
# app/workers/high_worker.rb class HighWorker include Sidekiq::Worker sidekiq_options queue: :high, retry: false def perform(csv_file_id) AbcCsvImporterService.call(csv_file_id) # 完了通知 or logging end end # AbcCsvImportクラスは実装無し。クラス内の例外についても対応する。thread safeのコードにする。(gemが提供するライブラリを使う場合も注意) # retry: falseなので、Dead Job Queueにはenqueueされません。
# config/application.rb ... config.active_job.queue_adapter = :sidekiq ....
# config/sidekiq.rb --- :verbose: false :timeout: 15 :concurrency: 2 staging: :concurrency: 5 production: :concurrency: 5 :queues: - high
# database.yml development: adapter: mysql2 encoding: utf8 database: my_db pool: 7 username: my_user password: my_password host: localhost ....
# config/initializes/sidekiq.rb Sidekiq.configure_server do |config| config.redis = { url: 'redis://localhost:6379', network_timeout: 5 } end Sidekiq.configure_client do |config| config.redis = { url: `redis://localhost:6379` network_timeout: 5 } end
ローカル上で動作することに限定するなら、設定ファイルをなくして、デフォルトにしてもいいです。上記のurlは、sidekiqのデフォルトになります。本番、ステージングなどある場合は環境別に変えましょう。network_timeoutオプションは、EC2を利用する都合timeout時間を伸ばしています。デフォルトは1です。
database poolと同値かそれ以下にconcurrencyを設定。
# csv_import_controller class CsvImportController < ApplicationController before_action :set_csv_file, only: %w[new create] before_action :set_csv_files, only: %w[index] def index; end def new; end def create if @csv_file.save redirect_to new_csv_import_path, notice: '保存に成功しました' else render :new, notice: '保存に失敗しました' end end private def csv_file_params return params.require(:csv_file).permit(CsvFile.column_names) if params[:csv_file] {} end def set_csv_file @csv_file = Csvfile.new(csv_file_params) end def csv_files # index用 end end
# app/model/csv_file.rb class CsvFile < ActiveRecord after_commit :import_data, on: :create def import_data CsvFileWorker.perform_async(id) end end
viewsは省きます。CSVファイルの入力フォームのイメージです。
bundle exec sidekiq -C config/sidekiq.yml
以上です。次回、AWSの構成、テストコード、redisなどの記事を書ければ書きます。色々ノウハウ溜まっているのでそのほかにElasticsearchなど。そのうち。
参考
Home · mperham/sidekiq Wiki · GitHub
Error Handling · mperham/sidekiq Wiki · GitHub
https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting#threading