Float を待ち時間に指定できるように `retry_on` が拡張された

rails/rails

retry_on のドキュメントは「秒単位での遅延(デフォルト: 3 秒)」と記述し、整数の wait: は動作していた。 しかし Float を直接指定した場合、determine_delayActiveSupport::DurationInteger のみをマッチ対象としていたため else ブランチに入り、内部エラーがスローされてジョブが再キューされなかった。 このバグは Float が除外された結果、元の例外が失われてデバッグが困難になるという実務上の問題を引き起こしていた。

背景

retry_on のドキュメントは「秒単位での遅延(デフォルト: 3 秒)」と記述し、整数の wait: は動作していた。 しかし Float を直接指定した場合、determine_delayActiveSupport::DurationInteger のみをマッチ対象としていたため else ブランチに入り、内部エラーがスローされてジョブが再キューされなかった。 このバグは Float が除外された結果、元の例外が失われてデバッグが困難になるという実務上の問題を引き起こしていた。

技術的な変更

activejob/lib/active_job/exceptions.rbdetermine_delay メソッドで、ケース分岐に Float を追加した。 変更前は when ActiveSupport::Duration, Integer だったが、変更後は when ActiveSupport::Duration, Integer, Float となり、seconds_or_duration_or_algorithm.to_i が実行されるようになった。

-        when ActiveSupport::Duration, Integer
+        when ActiveSupport::Duration, Integer, Float
           delay = seconds_or_duration_or_algorithm.to_i

Floatto_i によって小数部が切り捨てられ、整数秒として扱われるため、既存の遅延粒度は変わらない。 さらにテストコードが追加され、retry_on FloatWaitError, wait: 2.5 の動作を検証した。

+class FloatWaitError < StandardError; end
@@
   retry_on LongWaitError, wait: 1.hour, attempts: 10
+  retry_on FloatWaitError, wait: 2.5, attempts: 10
   retry_on ShortWaitTenAttemptsError, wait: 1.second, attempts: 10
+    test "float wait job" do
+      travel_to Time.now
+      random_amount = 1
+      delay_for_jitter = random_amount * 2 * ActiveJob::Base.retry_jitter
+
+      Kernel.stub(:rand, random_amount) do
+        RetryJob.perform_later "FloatWaitError", 2, :log_scheduled_at
+        assert_equal [
+          "Raised FloatWaitError for the 1st time",
+          "Next execution scheduled at #{(Time.now + 2.seconds + delay_for_jitter).to_f}",
+          "Successfully completed job"
+        ], JobBuffer.values
+      end
+    end

設計判断

マッチ対象に Float を明示的に追加 する方針が採られた。 代替案として Numeric での包括的マッチが議論されたが、既存コードの意図と後方互換性を保つため、最小限の変更である Float のみ追加が選択された。 これにより、整数と同様に秒単位での遅延が保証され、サブ秒対応はアダプタ側の実装次第で別途検討できる設計となっている。

まとめ

retry_on が Float 待ち時間を受け入れるようになり、ジョブ再試行時の例外置換が防止された。 変更はケース分岐への型追加のみで影響範囲が小さく、既存の遅延ロジックと互換性を維持しつつ、実務上の使い勝手を向上させている。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
0288282b

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文がタイトル直下にあり、背景・技術的変更・設計判断・まとめの各セクションが明確に分かれていて、まとめは単なる繰り返しになっていません。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは ```:言語:ファイルパス``` の形式で正しく記述され、PRリンクは [#57727](URL) 形式で正しいです。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門エンジニア向けの技術的内容で、初心者向けの過度な解説はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論→各論→結論の構成になっており、段落はトピックセンテンスで始まり、1段落1トピック、6文以下に収められています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと一致しており、変更点(Float の追加)やテスト追加が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている用語(determine_delay、ActiveSupport::Duration、Float、retry_on など)はPRとDiffで使用されているものと一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的説明はDiffの内容と合致し、Float が to_i で整数秒に変換される点や設計判断の背景が正しく記述されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の主張はすべてPRの説明・Diffによって裏付けられており、根拠のない推測や外部知識の付加はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #57727 が正しく記載されており、その他数値・識別子に誤りは見られません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の内容「Float wait in retry_on を受け入れる」ことを正確に日本語で表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTS、リリース日程など PR に含まれない外部情報は一切記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PR の記述と一致しています。