delayed 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 223856c2ccfb73e2f42eed3da86e70b0a819a575028ca1d0ddbebe0fc757c1d6
4
- data.tar.gz: b8d496dbd42774fcb7a5528cb4969b15a87cebd2c59899ad8dafa86438279874
3
+ metadata.gz: 6268c514bb90e5279b8265c4ce21eea8262ac4d539ff161c7f9eab12f15f17ba
4
+ data.tar.gz: eb0c1f81475163766a680eab603740a4632956fb415e4158430a67bb3998c381
5
5
  SHA512:
6
- metadata.gz: 5770b2945b0ff2e2a5f80a5cad81c8dd506c41519897e19ad29f973b57250891f3aa31c2d57135f69c960de12ea0724ad4bfa2bc68f445be6699851177a67b5e
7
- data.tar.gz: 89dbae3fb440d8cef88ed57131131ca7d3081b8039f772b6d88ebbd09332f7ffa9a2cfe09e5505d5c422ce69b82ae8344bf79d475022aa454594e87ef559e1d6
6
+ metadata.gz: 73686b95d83b336dcf268f4524fb8b512e64f61b58773b0884e8f1a4c30abc89532aaa0df4e1395d69417d2062ae7e948157c7cd5b3b7cb80982c68dbf798936
7
+ data.tar.gz: 9f3b7437e5772e0fe44b3f168cd32b78073b6c49b2fc208b713d946d4b48f14549646363856e3d62a7525059a7d841fbe0191a520af3dc06a71e3d258679b68e
@@ -140,6 +140,7 @@ module Delayed
140
140
  attr_reader :value
141
141
 
142
142
  delegate :to_i, to: :value
143
+ delegate :to_f, to: :value
143
144
  delegate :to_s, to: :name
144
145
 
145
146
  def initialize(value)
@@ -101,7 +101,12 @@ module Delayed
101
101
  pool = Concurrent::FixedThreadPool.new(jobs.length)
102
102
  jobs.each do |job|
103
103
  pool.post do
104
- success.increment if run_job(job)
104
+ self.class.lifecycle.run_callbacks(:thread, self, job) do
105
+ success.increment if perform(job)
106
+ end
107
+ rescue Exception => e # rubocop:disable Lint/RescueException
108
+ job_say job, "Job thread crashed with #{e.class.name}: #{e.message}", 'error'
109
+ job.error = e
105
110
  end
106
111
  end
107
112
 
@@ -117,12 +122,8 @@ module Delayed
117
122
  [success.value, total - success.value]
118
123
  end
119
124
 
120
- def run_thread_callbacks(job, &block)
121
- self.class.lifecycle.run_callbacks(:thread, self, job, &block)
122
- end
123
-
124
- def run(job)
125
- run_thread_callbacks(job) do
125
+ def perform(job)
126
+ self.class.lifecycle.run_callbacks(:perform, self, job) do
126
127
  metadata = {
127
128
  status: 'RUNNING',
128
129
  name: job.name,
@@ -141,17 +142,17 @@ module Delayed
141
142
  job.destroy
142
143
  end
143
144
  job_say job, format('COMPLETED after %.4f seconds', run_time)
144
- end
145
- true # did work
146
- rescue DeserializationError => e
147
- job_say job, "FAILED permanently with #{e.class.name}: #{e.message}", 'error'
145
+ true # did work
146
+ rescue DeserializationError => e
147
+ job_say job, "FAILED permanently with #{e.class.name}: #{e.message}", 'error'
148
148
 
149
- job.error = e
150
- failed(job)
151
- false # work failed
152
- rescue Exception => e # rubocop:disable Lint/RescueException
153
- self.class.lifecycle.run_callbacks(:error, self, job) { handle_failed_job(job, e) }
154
- false # work failed
149
+ job.error = e
150
+ failed(job)
151
+ false # work failed
152
+ rescue Exception => e # rubocop:disable Lint/RescueException
153
+ self.class.lifecycle.run_callbacks(:error, self, job) { handle_failed_job(job, e) }
154
+ false # work failed
155
+ end
155
156
  end
156
157
 
157
158
  # Reschedule the job in the future (when a job fails).
@@ -209,10 +210,6 @@ module Delayed
209
210
  reschedule(job)
210
211
  end
211
212
 
212
- def run_job(job)
213
- self.class.lifecycle.run_callbacks(:perform, self, job) { run(job) }
214
- end
215
-
216
213
  # The backend adapter may return either a list or a single job
217
214
  # In some backends, this can be controlled with the `max_claims` config
218
215
  # Either way, we map this to an array of job instances
data/lib/delayed.rb CHANGED
@@ -42,8 +42,8 @@ module Delayed
42
42
  mattr_accessor(:default_log_level) { 'info'.freeze }
43
43
  mattr_accessor(:plugins) do
44
44
  [
45
- Delayed::Plugins::Instrumentation,
46
45
  Delayed::Plugins::Connection,
46
+ Delayed::Plugins::Instrumentation,
47
47
  ]
48
48
  end
49
49
 
@@ -533,7 +533,7 @@ describe Delayed::Job do
533
533
  it 'fails after Worker.max_run_time' do
534
534
  Delayed::Worker.max_run_time = 1.second
535
535
  job = described_class.create payload_object: LongRunningJob.new
536
- worker.run(job)
536
+ worker.perform(job)
537
537
  expect(job.error).not_to be_nil
538
538
  expect(job.reload.last_error).to match(/expired/)
539
539
  expect(job.reload.last_error).to match(/Delayed::Worker\.max_run_time is only 1 second/)
@@ -558,7 +558,7 @@ describe Delayed::Job do
558
558
 
559
559
  it 'records last_error when destroy_failed_jobs = false, max_attempts = 1' do
560
560
  Delayed::Worker.max_attempts = 1
561
- worker.run(@job)
561
+ worker.perform(@job)
562
562
  @job.reload
563
563
  expect(@job.error).not_to be_nil
564
564
  expect(@job.last_error).to match(/did not work/)
@@ -580,7 +580,7 @@ describe Delayed::Job do
580
580
 
581
581
  it 're-schedules jobs with handler provided time if present' do
582
582
  job = described_class.enqueue(CustomRescheduleJob.new(99.minutes))
583
- worker.run(job)
583
+ worker.perform(job)
584
584
  job.reload
585
585
 
586
586
  expect((described_class.db_time_now + 99.minutes - job.run_at).abs).to be < 1
@@ -590,7 +590,7 @@ describe Delayed::Job do
590
590
  error_with_nil_message = StandardError.new
591
591
  expect(error_with_nil_message).to receive(:message).twice.and_return(nil)
592
592
  expect(@job).to receive(:invoke_job).and_raise error_with_nil_message
593
- expect { worker.run(@job) }.not_to raise_error
593
+ expect { worker.perform(@job) }.not_to raise_error
594
594
  end
595
595
  end
596
596
 
@@ -207,6 +207,13 @@ RSpec.describe Delayed::Priority do
207
207
  expect(described_class.new(101)).to eq described_class.new(101) # rubocop:disable RSpec/IdenticalEqualityAssertion
208
208
  end
209
209
 
210
+ it 'supports explicit casting' do
211
+ expect(described_class.new(0).to_i).to eq 0
212
+ expect(described_class.new(3).to_f).to eq 3.0
213
+ expect(described_class.new(10).to_s).to eq 'user_visible'
214
+ expect(described_class.new(:eventual).to_d).to eq '20'.to_d
215
+ end
216
+
210
217
  it 'suports coercion' do
211
218
  expect(described_class.new(0)).to eq 0
212
219
  expect(described_class.new(8)).to be > 5
data/spec/worker_spec.rb CHANGED
@@ -239,5 +239,35 @@ describe Delayed::Worker do
239
239
 
240
240
  expect(performances.value).to eq(1)
241
241
  end
242
+
243
+ it 'wraps perform and cleanup, even when perform raises' do
244
+ events = []
245
+ last_error = nil
246
+
247
+ plugin = Class.new(Delayed::Plugin) do
248
+ callbacks do |lifecycle|
249
+ lifecycle.around(:thread) do |_, &blk|
250
+ events << :thread_start
251
+ blk.call
252
+ events << :thread_end
253
+ end
254
+ lifecycle.around(:perform) do |_, job, &blk|
255
+ events << :perform_start
256
+ blk.call.tap do
257
+ last_error = job.last_error
258
+ events << :perform_end
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ Delayed.plugins << plugin
265
+
266
+ Delayed::Job.enqueue ErrorJob.new
267
+ described_class.new.work_off
268
+
269
+ expect(events).to eq %i(thread_start perform_start perform_end thread_end)
270
+ expect(last_error).to match(/did not work/) # assert that cleanup happened before `:perform_end`
271
+ end
242
272
  end
243
273
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
@@ -18,7 +18,7 @@ authors:
18
18
  - Tobias Lütke
19
19
  bindir: bin
20
20
  cert_chain: []
21
- date: 2025-01-24 00:00:00.000000000 Z
21
+ date: 2025-04-03 00:00:00.000000000 Z
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
24
24
  name: activerecord
@@ -137,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  requirements: []
140
- rubygems_version: 3.6.2
140
+ rubygems_version: 3.6.6
141
141
  specification_version: 4
142
142
  summary: a multi-threaded, SQL-driven ActiveJob backend used at Betterment to process
143
143
  millions of background jobs per day