app/models/good_job/execution.rb in good_job-3.15.14 vs app/models/good_job/execution.rb in good_job-3.16.0
- old
+ new
@@ -1,6 +1,7 @@
# frozen_string_literal: true
+
module GoodJob
# ActiveRecord model that represents an +ActiveJob+ job.
class Execution < BaseExecution
include Lockable
include Filterable
@@ -260,12 +261,16 @@
execution = nil
result = nil
unfinished.dequeueing_ordered(parsed_queues).only_scheduled.limit(1).with_advisory_lock(unlock_session: true, select_limit: queue_select_limit) do |executions|
execution = executions.first
break if execution.blank?
- break :unlocked unless execution&.executable?
+ unless execution.executable?
+ result = ExecutionResult.new(value: nil, unexecutable: true)
+ break
+ end
+
yield(execution) if block_given?
result = execution.perform
end
execution&.run_callbacks(:perform_unlocked)
@@ -371,14 +376,18 @@
current_thread.execution_interrupted = performed_at
if discrete?
interrupt_error_string = self.class.format_error(GoodJob::InterruptError.new("Interrupted after starting perform at '#{performed_at}'"))
self.error = interrupt_error_string
- discrete_executions.where(finished_at: nil).where.not(performed_at: nil).update_all( # rubocop:disable Rails/SkipsModelValidations
+ self.error_event = ERROR_EVENT_INTERRUPTED if self.class.error_event_migrated?
+
+ discrete_execution_attrs = {
error: interrupt_error_string,
- finished_at: Time.current
- )
+ finished_at: Time.current,
+ }
+ discrete_execution_attrs[:error_event] = GoodJob::DiscreteExecution.error_events[GoodJob::DiscreteExecution::ERROR_EVENT_INTERRUPTED] if self.class.error_event_migrated?
+ discrete_executions.where(finished_at: nil).where.not(performed_at: nil).update_all(discrete_execution_attrs) # rubocop:disable Rails/SkipsModelValidations
end
end
if discrete?
transaction do
@@ -403,29 +412,53 @@
handled_error = value
value = nil
end
handled_error ||= current_thread.error_on_retry || current_thread.error_on_discard
+ error_event = if handled_error == current_thread.error_on_discard
+ ERROR_EVENT_DISCARDED
+ elsif handled_error == current_thread.error_on_retry
+ ERROR_EVENT_RETRIED
+ elsif handled_error == current_thread.error_on_retry_stopped
+ ERROR_EVENT_RETRY_STOPPED
+ elsif handled_error
+ ERROR_EVENT_HANDLED
+ end
+
instrument_payload.merge!(
value: value,
handled_error: handled_error,
- retried: current_thread.execution_retried
+ retried: current_thread.execution_retried,
+ error_event: error_event
)
- ExecutionResult.new(value: value, handled_error: handled_error, retried: current_thread.execution_retried)
+ ExecutionResult.new(value: value, handled_error: handled_error, error_event: error_event, retried: current_thread.execution_retried)
rescue StandardError => e
+ error_event = if e.is_a?(GoodJob::InterruptError)
+ ERROR_EVENT_INTERRUPTED
+ elsif e == current_thread.error_on_retry_stopped
+ ERROR_EVENT_RETRY_STOPPED
+ else
+ ERROR_EVENT_UNHANDLED
+ end
+
instrument_payload[:unhandled_error] = e
- ExecutionResult.new(value: nil, unhandled_error: e)
+ ExecutionResult.new(value: nil, unhandled_error: e, error_event: error_event)
end
end
job_error = result.handled_error || result.unhandled_error
if job_error
error_string = self.class.format_error(job_error)
self.error = error_string
- discrete_execution.error = error_string if discrete_execution
+ self.error_event = result.error_event if self.class.error_event_migrated?
+ if discrete_execution
+ discrete_execution.error = error_string
+ discrete_execution.error_event = result.error_event if discrete_execution.class.error_event_migrated?
+ end
else
self.error = nil
+ self.error_event = nil if self.class.error_event_migrated?
end
reenqueued = result.retried? || retried_good_job_id.present?
if result.unhandled_error && GoodJob.retry_on_unhandled_error
if discrete_execution