背景
昔作られていたオンライン処理で、データ量が想定より大きくなり過ぎたせいで
画面上で処理するとタイムアウトになってしまっていた。
タイムアウトと言ってもUI側だけで、バックグラウンドの処理は正常に行われている。
幸い社内のみ利用されている機能で、月一の処理だったので
保守係が手動で処理していた。
これをバッチ化できないかを検討。
業務要件
・ユーザ(経理)の方で任意の日付(処理日)を入れる必要がある為、オンライン上での入力は維持する必要がある。
・会計締め処理に合わせる必要がある為、なる早めの実行が必要。
・処理が終わった後、ユーザが作られたデータを確認する必要がある。
技術要件
・既に色んな機能がお互い依存しているスパゲティコードになっているので、修正箇所は最小限にしたい。
→既存の処理を切り出して非同期処理化する。
・ruby1.9, rails3.2.12
非同期処理実装のため検討したこと
Active Job
rails4.2以上対応だが、現在のバージョンは3.2.12だった為、断念
Delayed Job
キュー管理用のテーブルが必要で、Sidekiqより参考資料が少なそう。
Sidekiq
redisのインストールが必要だが、今のバージョンでも使えそうだったので採用
[Ruby on Rails] Sidekiq で非同期処理を実装する
Sidekiqのバージョン選びについて
・普通にインストール→Sidekiq 5.0.3が入った。
generateコマンドで使えるか確認
$ rails generate --help Gem Load Error is: Sidekiq 5.0.3 does not support Ruby versions below 2.2.2.→Requires Ruby 2.5+ and Redis 4.0+
ちなみに今のrubyバージョンは
$ ruby -v ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux] $ gem search ^sidekiq$ --all Error loading RubyGems plugin "/usr/local/lib/ruby/gems/1.9.1/gems/yard-0.8.5.2/lib/rubygems_plugin.rb": can't modify frozen Hash (RuntimeError) YAML safe loading is not available. Please upgrade psych to a version that supports safe loading (>= 2.0). *** REMOTE GEMS *** sidekiq (6.0.3, 6.0.2, 6.0.1, 6.0.0, 5.2.7, 5.2.6, 5.2.5, 5.2.4, 5.2.3, 5.2.2, 5.2.1, 5.2.0, 5.1.3, 5.1.2, 5.1.1, 5.1.0, 5.0.5, 5.0.4, 5.0.3, 5.0.2, 5.0.1, 5.0.0, 4.2.10, 4.2.9, 4.2.8, 4.2.7, 4.2.6, 4.2.5, 4.2.4, 4.2.3, 4.2.2, 4.2.1, 4.2.0, 4.1.4, 4.1.3, 4.1.2, 4.1.1, 4.1.0, 4.0.2, 4.0.1, 4.0.0, 3.5.4, 3.5.3, 3.5.2, 3.5.1, 3.5.0, 3.4.2, 3.4.1, 3.4.0, 3.3.4, 3.3.3, 3.3.2, 3.3.1, 3.3.0, 3.2.6, 3.2.5, 3.2.4, 3.2.3, 3.2.2, 3.2.1, 3.2.0, 3.1.4, 3.1.3, 3.1.2, 3.1.1, 3.1.0, 3.0.2, 3.0.1, 3.0.0, 2.17.8, 2.17.7, 2.17.6, 2.17.5, 2.17.4, 2.17.3, 2.17.2, 2.17.1, 2.17.0, 2.16.1, 2.16.0, 2.15.2, 2.15.1, 2.15.0, 2.14.1, 2.14.0, 2.13.1, 2.13.0, 2.12.4, 2.12.3, 2.12.1, 2.12.0, 2.11.2, 2.11.1, 2.11.0, 2.10.1, 2.10.0, 2.9.0, 2.8.0, 2.7.5, 2.7.4, 2.7.3, 2.7.2, 2.7.1, 2.7.0, 2.6.5, 2.6.4, 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.4, 2.5.3, 2.5.2, 2.5.1, 2.5.0, 2.4.0, 2.3.3, 2.3.2, 2.3.1, 2.3.0, 2.2.1, 2.2.0, 2.1.1, 2.1.0, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 1.2.1, 1.2.0, 1.1.4, 1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.0, 0.11.2, 0.11.1, 0.11.0, 0.10.1, 0.10.0, 0.9.1, 0.9.0, 0.8.0, 0.7.0, 0.6.0, 0.5.1, 0.5.0)
2.17.8でインストール成功
Gemfile
# 非同期実行用 gem 'sidekiq', '2.17.8'
デフォルトだとログが標準出力になるらしいので
Railsのログとして出力されるように変更する
$ cat config/initializers/sidekiq.rb Sidekiq::Logging.logger = Rails.logger
Sidekiq のロギングに Rails logger を利用する
Redisのインストール
redisをインストールせずにsidekiqのアプリケーションを起動すると、下記のエラーになってしまう。
[FATAL] [2019-12-19 12:39:12 +0900] [b2b2ab87ca2f7d6425d549be8609b04b] Error connecting to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED)
apt install redis-server
コードの改修
コントローラ側の処理をワーカクラスに切り出し
app/workers/monthly_billing_request.rb
コントローラではワーカをキューに入れるように変更
class System::BillsController < ApplicationController def create : logger.debug('clear retry queue') Sidekiq::Queue.new.clear Sidekiq::ScheduledSet.new.clear logger.debug('MonthlyBillingRequest queuing start') MonthlyBillingRequest.perform_in(1.seconds, scheduled_at) logger.debug('MonthlyBillingRequest queuing end') :
ワーカはWorkerをincludeして実装
class MonthlyBillingRequest include Sidekiq::Worker sidekiq_options queue: :event, retry: false def perform(scheduled_at) ## 何か処理 end end
キューの確認について
バッチを実行するとキューに入るが、ちゃんとキューに入っているか・キューから実行されているかなどの確認をする為には redisで確認する必要がある。
redis-cliRedis に保存されてる値を見ようと思った時に覚えておきたい redis コマンド
画面から連続でボタンが押されると、キューも複数生成されてしまっていた。
アプリケーション側で制御する必要があるが、取り敢えず間違ったキューは削除したい。
Redisのデータを削除する方法
結局どうなったのか
非同期処理をしてもwebインスタンスに負荷が掛かることは変わらないことで
バッチ実行時にバッチ用のインスタンスを作って実行することで
この案は廃止された。