Sidekiq アンチパターンのまとめ
Sidekiq アンチパターン
業務でsidekiqを利用するケースがあったのですが、sidekiqのアンチパターンについて知らなかったのでまとめました。
1. 命名規則について
ワーカーの名前は後から変更するのは後から変更するのは大変です。
ワーカーの命名規則をつけるときは動作を表すようにしましょう。
BAD
1. WebhookWorker 2. ImportWorker
この命名規則はどうでしょうか?
1はwebhookで何をするのかの情報が不十分です。
2は何をimportするのかの情報が不十分です。
GOOD
1. WebhookNotificationWorker 2. CrewImportWorker
2. 非同期処理内の例外握り潰し
def perform(arg) # something to do rescue => e logger.error "#{e.class}: #{e.message}" end
非同期の中で例外握りつぶしをするのはNGです。
perform 実行中にいかなる例外が発生しようとも rescue 節でキャッチしてしまうので、 perform を呼び出した worker はジョブが成功したものとみなしてしまいます。
つまり、失敗したことに気づかない状態になってしまいます。
def perform(arg) # something to do rescue => e raise '処理に失敗しました><' end
resucueの中で発生した例外を RuntimeError で上書きしてしまうと。
performの中でどのような例外が発生したか、わからなくなってしまうのでこちらもNGです。
def perform(arg) # something to do rescue => e 1 / Random.rand(2) # 50% chance to raise ZeroDivisionError raise e end
resucueの中で例外が発生し得る処理を記述するのもNGです。
rescueの中では例外が発生すると、rescueの意味がなくなってしまいます。
引数について
performの引数を実装途中で変更するのは非常に危険です。
class WebhookWorker include Sidekiq::Worker def perform(url, channel, message) payload = {channel: channel, message: message} RestClient.post(url, payload.to_json) end end
もし途中でWebhook パラメータを追加/変更したい場合に単純にワーカーが受け取れる引数を増やしたらどうなるでしょうか?
class WebhookWorker include Sidekiq::Worker def perform(url, channel, username, message) payload = {channel: channel, message: message, username: username} RestClient.post(url, payload.to_json) end end
Sidekiq ではジョブを予約した時の変数との対応は実行時に考慮してもらえないので思わぬトラブルを招きます。
WebhookWorker.perform_async('https://hooks.example.com/T00000000/XXXXX', 'general', 'hello, webhooks!')
このように引数の順序がメチャクチャになってしまいます
url = 'https://hooks.example.com/T00000000/XXXXX' channel = 'general' username = 'hello, webhooks! message = nil