Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/que/job_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ module Que
%{
UPDATE public.que_jobs
SET error_count = error_count + 1,
expired_at = now()
WHERE id = $1::bigint
expired_at = now(),
last_error_message = left($1::text, 500),
last_error_backtrace = left($2::text, 10000)
WHERE id = $3::bigint
}

SQL[:destroy_job] =
Expand Down Expand Up @@ -101,7 +103,15 @@ def expire
return unless que_target

if id = que_target.que_attrs[:id]
Que.execute :expire_job, [id]
values = []

if e = que_target.que_error
values << "#{e.class}: #{e.message}".slice(0, 500) << e.backtrace.join("\n").slice(0, 10000)
else
values << nil << nil
end

Que.execute :expire_job, values << id
end

que_target.que_resolved = true
Expand Down
13 changes: 10 additions & 3 deletions lib/que/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,15 @@ def work_job(metajob)

max_retry_count = job_class.resolve_que_setting(:maximum_retry_count)

last_error_message = "#{error.class}: #{error.message}".slice(0, 500)
last_error_backtrace = (error.backtrace || []).join("\n").slice(0, 10000)

if max_retry_count && error_count > max_retry_count
Que.execute :expire_job, [job.fetch(:id)]
Que.execute :expire_job, [
last_error_message,
last_error_backtrace,
job.fetch(:id),
]
else
delay =
job_class.
Expand All @@ -164,8 +171,8 @@ def work_job(metajob)

Que.execute :set_error, [
delay,
"#{error.class}: #{error.message}".slice(0, 500),
(error.backtrace || []).join("\n").slice(0, 10000),
last_error_message,
last_error_backtrace,
job.fetch(:id),
]
end
Expand Down
27 changes: 27 additions & 0 deletions spec/que/job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,33 @@ def run
end
end

it "should store error when a job expires after maximum retry count is exceeded" do
TestJobClass.class_eval do
def run
raise "Uh-oh!"
end
end

TestJobClass.maximum_retry_count = 0

assert_raises(StandardError) do
enqueue_method.call
execute
end

if should_persist_job
assert_empty active_jobs_dataset
refute_empty expired_jobs_dataset

job = expired_jobs_dataset.first
assert_equal 1, job[:error_count]
assert_equal "RuntimeError: Uh-oh!", job[:last_error_message]
assert_match(/\A#{__FILE__}/, job[:last_error_backtrace].split("\n").first)
else
assert_empty jobs_dataset
end
end

it "should make it easy to override the default resolution action" do
TestJobClass.class_eval do
def run
Expand Down
13 changes: 9 additions & 4 deletions spec/que/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def run(*args)
end
end

it "should mark the job as expired" do
it "should mark the job as expired and store error" do
job = WorkerJob.enqueue

assert_equal 1, jobs_dataset.update(error_count: 14)
Expand All @@ -324,13 +324,15 @@ def run(*args)

run_jobs

a = jobs_dataset.select_map([:expired_at, :error_count])
a = jobs_dataset.select_map([:expired_at, :error_count, :last_error_message, :last_error_backtrace])
assert_equal 1, a.length

expired_at, error_count = a.first
expired_at, error_count, last_error_message, last_error_backtrace = a.first

assert_in_delta expired_at, Time.now, QueSpec::TIME_SKEW
assert_equal 16, error_count
assert_equal last_error_message, "RuntimeError: Blah!"
assert_match(/\A#{__FILE__}/, last_error_backtrace)
end

describe "when that value is custom" do
Expand Down Expand Up @@ -376,9 +378,12 @@ def run(*args)
assert_equal 1, ds.update(error_count: 15)
run_jobs

expired_at, error_count = ds.select_map([:expired_at, :error_count]).first
expired_at, error_count, last_error_message, last_error_backtrace =
ds.select_map([:expired_at, :error_count, :last_error_message, :last_error_backtrace]).first
assert_in_delta expired_at, Time.now, QueSpec::TIME_SKEW
assert_equal 16, error_count
assert_equal "NameError: uninitialized constant NonexistentJobClass", last_error_message
refute_empty last_error_backtrace
end
end

Expand Down
Loading