ActiveJob で再エンキュー時に残っていた enqueue_error をクリア
ActiveJob の enqueue メソッドが再エンキュー時に enqueue_error をリセットしないため、失敗後のエラー情報が残り続けていました。この PR は同時に successfully_enqueued をリセットしている箇所に enqueue_error のクリア処理を追加し、ジョブ状態の一貫性を保ちます。
背景
ActiveJob::Enqueuing#enqueue は呼び出しごとに self.successfully_enqueued = false としてエンキュー成功フラグを初期化していますが、self.enqueue_error はリセットせずに保持したままでした。結果として、一度 EnqueueError が発生したジョブインスタンスを再エンキューすると、成功したにも関わらず古いエラーオブジェクトが残り、job.enqueue_error が非 nil の状態になります。
典型的なシナリオは次のとおりです。最初の job.enqueue がアダプタの一時的な障害で ActiveJob::EnqueueError をスローし、ジョブは失敗状態になります。その直後に同一インスタンスで再度 job.enqueue を呼び出すと正常にキューに入りますが、job.successfully_enqueued? は true になる一方で job.enqueue_error は依然として古いエラーオブジェクトを保持したままです。
この残存エラーは ActiveJob::StructuredEventSubscriber#enqueue が例外情報を取得する際に顕在化します。イベントペイロードに :exception_object が無い場合、サブスクライバは job.enqueue_error を参照して例外クラス・メッセージを記録するため、実際には成功したジョブがエラーとして扱われてしまいます。
技術的な変更
enqueue の冒頭で self.enqueue_error = nil を追加し、successfully_enqueued と同時にエラー状態もリセットするようにしました。このシンプルな代入はジョブオブジェクトの状態管理を一元化し、失敗後の再利用時に残留情報が残らないことを保証します。
@@ -82,6 +82,7 @@ def enqueue(options = {})
set(options)
self.successfully_enqueued = false
+ self.enqueue_error = nil
raw_enqueue
テストスイートにも新しいケースが追加され、EnqueueErrorAdapter が最初は例外を投げ、二回目は正常にエンキューするシナリオで enqueue_error が nil になることを検証しています。
test "enqueue_error is cleared when the same job is successfully re-enqueued" do
EnqueueErrorJob::EnqueueErrorAdapter.should_raise_sequence = [ true, false ]
job = EnqueueErrorJob.new
assert_equal false, job.enqueue
assert_equal ActiveJob::EnqueueError, job.enqueue_error.class
assert_equal job, job.enqueue
assert job.successfully_enqueued?
assert_nil job.enqueue_error
ensure
EnqueueErrorJob::EnqueueErrorAdapter.should_raise_sequence = []
end
設計判断
enqueue_error を successfully_enqueued と同時にリセットする設計は、ジョブオブジェクトの状態遷移を原子的に扱うという方針に基づいています。エラーフラグと成功フラグが常にペアで更新されることで、外部のイベントサブスクライバが状態を誤解するリスクを根本的に排除します。
この変更は既存の API 互換性に影響を与えません。enqueue が失敗しなかった場合は従来通り enqueue_error が nil になるだけで、呼び出し側のコードは追加の条件分岐を必要としません。その上で、ジョブのライフサイクル管理がより堅牢になるという利点が得られます。
まとめ
ActiveJob::Enqueuing#enqueue にエラーリセットを組み込んだことで、再エンキュー時の stale enqueue_error が排除され、ジョブ状態とイベント情報の整合性が向上しました。これにより、構造化イベントの正確なモニタリングと、ジョブオブジェクトの再利用が安全に行えるようになります。