Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
delayed (0.7.2)
delayed (0.8.0)
activerecord (>= 5.2)
concurrent-ruby

Expand Down
2 changes: 1 addition & 1 deletion delayed.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']
spec.summary = 'a multi-threaded, SQL-driven ActiveJob backend used at Betterment to process millions of background jobs per day'

spec.version = '0.7.2'
spec.version = '0.8.0'
spec.metadata = {
'changelog_uri' => 'https://github.com/betterment/delayed/blob/main/CHANGELOG.md',
'bug_tracker_uri' => 'https://github.com/betterment/delayed/issues',
Expand Down
1 change: 1 addition & 0 deletions lib/delayed/priority.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def method_missing(method_name, *args)
attr_reader :value

delegate :to_i, to: :value
delegate :to_f, to: :value
delegate :to_s, to: :name

def initialize(value)
Expand Down
20 changes: 10 additions & 10 deletions lib/delayed/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,17 @@ def perform(job)
job.destroy
end
job_say job, format('COMPLETED after %.4f seconds', run_time)
true # did work
rescue DeserializationError => e
job_say job, "FAILED permanently with #{e.class.name}: #{e.message}", 'error'

job.error = e
failed(job)
false # work failed
rescue Exception => e # rubocop:disable Lint/RescueException
self.class.lifecycle.run_callbacks(:error, self, job) { handle_failed_job(job, e) }
false # work failed
end
true # did work
rescue DeserializationError => e
job_say job, "FAILED permanently with #{e.class.name}: #{e.message}", 'error'

job.error = e
failed(job)
false # work failed
rescue Exception => e # rubocop:disable Lint/RescueException
self.class.lifecycle.run_callbacks(:error, self, job) { handle_failed_job(job, e) }
false # work failed
end

# Reschedule the job in the future (when a job fails).
Expand Down
7 changes: 7 additions & 0 deletions spec/delayed/priority_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@
expect(described_class.new(101)).to eq described_class.new(101) # rubocop:disable RSpec/IdenticalEqualityAssertion
end

it 'supports explicit casting' do
expect(described_class.new(0).to_i).to eq 0
expect(described_class.new(3).to_f).to eq 3.0
expect(described_class.new(10).to_s).to eq 'user_visible'
expect(described_class.new(:eventual).to_d).to eq '20'.to_d
end

it 'suports coercion' do
expect(described_class.new(0)).to eq 0
expect(described_class.new(8)).to be > 5
Expand Down
30 changes: 30 additions & 0 deletions spec/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,35 @@

expect(performances.value).to eq(1)
end

it 'wraps perform and cleanup, even when perform raises' do
events = []
last_error = nil

plugin = Class.new(Delayed::Plugin) do
callbacks do |lifecycle|
lifecycle.around(:thread) do |_, &blk|
events << :thread_start
blk.call
events << :thread_end
end
lifecycle.around(:perform) do |_, job, &blk|
events << :perform_start
blk.call.tap do
last_error = job.last_error
events << :perform_end
end
end
end
end

Delayed.plugins << plugin

Delayed::Job.enqueue ErrorJob.new
described_class.new.work_off

expect(events).to eq %i(thread_start perform_start perform_end thread_end)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

expect(last_error).to match(/did not work/) # assert that cleanup happened before `:perform_end`
end
end
end