技術ブログ

(技術系中心)基本自分用備忘録なので、あくまで参考程度でお願いします。

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

参考

Sidekiq アンチパターン: 序 - SmartHR Tech Blog