`retry_on` の `wait:` プロックで省略引数を受け付けるよう修正
retry_on のオプション wait: に渡す Proc が省略引数を持つ場合でも正しく呼び出せるよう、Arity 判定ロジックが改良されました。これにより、既存の 1 引数 Proc と同様にオプション引数付き Proc もエラーなく利用でき、バックグラウンドジョブのリトライスケジュール設定の柔軟性が向上します。
背景
ActiveJob のリトライ機構は wait: に Proc を指定でき、実行回数や例外情報に基づく遅延時間を算出します。従来は algorithm.arity == 1 の場合に 1 引数で、以外は 2 引数で呼び出す実装で、arity が -1(省略引数付き Proc)でも 2 引数で呼び出され ArgumentError が発生していました。
この問題は、->(executions = 0) { … } のように引数にデフォルト値を設定した Proc が対象です。テストケースが追加されるまで実運用での障害は顕在化しにくく、PR では 1 本のプロダクションラインで例外が報告されたことが発端となっています。
技術的な変更
activejob/lib/active_job/exceptions.rb の determine_delay メソッドで、Arity 判定式が以下のように変更されました。
変更前:
algorithm.arity == 1 ? algorithm.call(executions) : algorithm.call(executions, error)
変更後:
algorithm.arity == 2 || algorithm.arity < -1 ? algorithm.call(executions, error) : algorithm.call(executions)
新条件は次の 2 つを評価します。① arity が 2 の場合(明示的に 2 引数を受け取る Proc)② arity が -1 未満 の場合(省略引数や可変長引数 *rest を含む Proc)。この判定により、->(executions = 0) や ->(executions, *rest) でも適切に 1 引数で呼び出されます。
テストコードも同時に拡充され、activejob/test/jobs/retry_job.rb に OptionalArgWaitError 用の retry_on 定義が追加され、activejob/test/cases/exceptions_test.rb に新しいテスト "custom wait proc with an optional argument" が実装されました。テストは travel_to で時刻を固定し、期待されるスケジュール時刻が正しく記録されることを検証しています。
設計判断
この修正は API を増やさず既存の retry_on オプションだけで対応 するという方針の下で実装されました。代替案としては wait: 用に別のキー(例: wait_with_options:)を導入する案が議論されましたが、後方互換性と既存コードへの影響最小化の観点から、Arity 判定ロジックの拡張が選択されました。
判定ロジックは 「arity が 2 もしくは -1 未満」 というシンプルな式にまとめられ、可読性を保ちつつ省略引数・可変長引数の両方を包括的に扱えるようになりました。これにより、開発者は wait: に自由な Proc を記述でき、リトライ遅延の計算ロジックをより表現力豊かに記述可能です。
まとめ
retry_on の wait: プロックが省略引数を受け取るケースを考慮した Arity 判定へ改良されたことで、ArgumentError が除去され、既存のリトライ設定と互換性を保ちつつ新たな柔軟性が提供されました。テストも追加されているため、今後のリリースで安定した挙動が保証されます。