去年、eKYCを利用した本人確認機能を開発していたのですが、導入しようとしたオープンソースにバグがあり、そのままでは開発が進められない事態となりました。
この状況を打破すべく、オープンソースにコミットを積んで運良く直すことができたので、背景や解決までに至ったプロセスなどを紹介します。
背景
ユーザーが本人確認申請時に個人情報をeKYCへ送信した後、正しくレスポンスが返ってきた場合はユーザーをeKYCの本人確認手続き画面へ誘導する必要がありました。送信するだけであれば同期処理で良いのですが、エラーのレスポンスが返された時にその場で再送信をユーザーへ促したかったことと、レスポンスが正しく返ってきた時はその場で本人確認手続き画面へ誘導させたかったため、なるべく、ユーザーの待ち時間が発生しないように非同期処理にしなければなりませんでした。
ただし、eKYCへの同時リクエスト数が5までであっためSidekiqで制御する必要がありました。
Sidekiq単体で制御を行う場合、有料版のSidekiq Enterpriseへ切り替えなければなりませんでした。しかし、利用料金が高額なことと開発期限が約1ヶ月後に迫っていたため、予算申請から導入までの時間も考えると開発負荷を上げてしまう懸念がありました。
そこで、オープンソースのsidekiq-limit_fetchというサードパーティを使うことで、同時リクエスト数を制限しようとしました。しかし、ここでも問題がありsidekiq-limit_fetchを実際に導入してみるとバグが存在していたためそのまま使用することが困難でした。
対応方針
sidekiq-limit_fetchで同時リクエスト数制限を実現させるためにできそうなことは、2つありました。
- Sidekiqをダウングレードする
- sidekiq-limit_fetchのバグを修正する
sidekiq-limit_fetchの導入時、開発環境に入っていたSidekiqのバージョンはv7でした。v7は半年以内にリリースされたばかりだったこともあり、sidekiq-limit_fetchがまだv7に完全に対応できていない状況でした。Sidekiqをv6にダウングレードするとエラーが出ずに動作することを確認できましたが、メジャーバージョンを下げることは影響範囲のことを考慮すると懸命でないと判断し、sidekiq-limit_fetchのバグ修正を優先させました。
発生していたバグ
問題となるsidekiq-limit_fetchのバグは2つありました。
- キューの設定が読み込めない
- Sidekiq::BasicFetchの引数に渡す値が間違えていた
キューの設定が読み込めない
原因
sidekiq.yml
に設定されているキューの名前を取得しto_s
もしくはto_sym
で型を変換する処理があったのですが、コード1のように、重みづけも設定されていると配列が取得されるため型の変換でエラーが起きていました。
コード1
:queues:
- ['high_priority', 2]
- ['low_priority', 1]
発生していたエラー
undefined method `to_sym' for ["active_storage_analysis", 4]:Array
queue.process_limit = @process_limits[queue_name.to_s] || @process_limits[queue_name.to_sym]
^^^^^^^
Did you mean? to_s
to_set
/Users/me/.rvm/gems/ruby-3.1.2@project/gems/sidekiq-limit_fetch-4.4.0/lib/sidekiq/limit_fetch/queues.rb:121:in `apply_process_limit_to_queue'
解決方法
キューを受け取った時に、文字列か配列かを判定して必ずキューの名前だけを取得する処理を入れました。
実装した修正コミット
@queues = config[:queues].map do |queue|
if queue.is_a? Array
queue.first
else
queue
end
end.uniq
GitHubのコミット
Sidekiq::BasicFetchの引数に渡す値が間違えていた
原因
sidekiq-limit_fetchの処理でSidekiq::BasicFetch
にSidekiqのconfigを渡す処理があります。Sidekiq v6ではSidekiqモジュール内にconfigが含まれており、sidekiq-limit_fetchの実装もSidekiqモジュールからconfigを取得する実装になっていました。しかし、Sidekiq v7からconfigは別モジュールに切り出されてconfigの取得方法が変わったため、sidekiq-limit_fetchもSidekiqの変更に合わせて実装を変える必要がありました。
解決方法
Sidekiqのバージョンが7であるときは、Configモジュール経由でconfigを取得するようにしました。
実装した修正コミット
Sidekiq::BasicFetch.new(post_7? ? Sidekiq.default_configuration.default_capsule : config).bulk_requeue(*args)
GitHubのコミット
修正してマージされたPR