Hisakeyのブログ

エンジニアが色々呟くブログです。

Sidekiqに渡せる引数について理解する

概要

Sidekiqは、Ruby on Railsアプリケーションでよく使われる非同期のバックグラウンドジョブ処理ライブラリです。バックグラウンドジョブを使うことで、ユーザーが直接待つ必要のない処理を非同期で実行することができます

しかし、Sidekiqではジョブに渡すことができる引数に制限があり、その制限を理解していなかったので、予期せぬエラーを出してしまったので、記事にしてみました

内容

渡せないデータ型がある

Sidekiqに渡せないデータ型がいくつか存在します。これらはJSONに変換できないため、引数として使用するとエラーが発生します。

  • シンボル(例: :exampleJSONではシンボルを文字列に変換する必要があります)
  • ファイルやIOオブジェクト(例: File.open('path/to/file')
  • ProcやLambda(例: -> { puts "hello" }
  • クラスやモジュール(例: MyClass.new

例えば、ジョブにシンボルを渡そうとすると、以下のようなエラーが発生します:

class MyWorker
  include Sidekiq::Worker

  def perform(status)
    # 実行時に:statusが引数として渡される
  end
end

# エラーになる可能性のあるジョブ
MyWorker.perform_async(:completed)

この場合、:completedというシンボルはJSONに変換できないため、ArgumentErrorが発生します。

Sidekiqが期待する引数

では、Sidekiqに渡せる引数は何でしょうか? Sidekiqは内部でジョブをキューに入れる際に、引数をJSONシリアライズしています。そのため、Sidekiqがサポートする引数は、JSON形式に変換可能なデータ型に限られます。具体的には以下のデータ型が使用可能です:

  • 数値(例: 1, 3.14
  • 文字列(例: "こんにちは", "example@example.com"
  • 真偽値(例: true, false
  • 配列(例: [1, "foo", true]
  • ハッシュ(例: {"name": "太郎", "age": 32}
  • nil(例: nil

JSONフォーマットで表現できるデータ型です。

github.com

Sidekiqでは、引数がJSONシリアライズされるため、データ型が変換される際に注意が必要です。

  • シンボルが文字列に変換される:例えば、:statusというシンボルを渡すと、"status"という文字列として扱われます。

こうした変換に注意しないと、ジョブ内で意図した通りにデータが扱われないことがあります。

安全に引数を渡すためのベストプラクティス

Sidekiqに引数を渡す際には、以下のベストプラクティスを守ることで、エラーを回避し、ジョブを安全にキューイングすることができます。

  • 複雑なオブジェクトを避ける:複雑なオブジェクト(例: クラスインスタンスやファイル)は、シリアライズできないため、基本的なデータ型に変換して渡すようにしましょう。例えば、オブジェクトのIDや属性のみを渡すことが有効です。
  class MyWorker
    include Sidekiq::Worker

    def perform(user_id)
      user = User.find(user_id)
      # userオブジェクトを操作
    end
  end

  # userオブジェクト全体ではなくIDを渡す
  MyWorker.perform_async(user.id)
  • ファイルや画像データを処理する場合は、IDやパスを渡す:ファイル自体をSidekiqに渡すのではなく、ファイルのパスやIDを渡し、ジョブ内でファイルを処理するようにします。

まとめ

Sidekiqでジョブを実行する際には、引数として渡せるデータ型に制約があるため、JSONシリアライズ可能な基本データ型(数値、文字列、配列、ハッシュなど)に限定する必要があります。また、複雑なオブジェクトやシンボルなどを渡そうとするとエラーが発生するため、シンプルなデータ型に変換してから渡すのがよさそうです。

今回は、テストを書いている中で気づけたのでよかったのですが、予期せぬ挙動には気をつけましょう