delayed 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae36c9e652d4fb6ce28f8897b0e7b03b7777ce9907a74973924111b735bca3ae
4
- data.tar.gz: 0d4c27d0bf1f7e256fa85914086a0711c6406b4be5e88f211eccbd921c001718
3
+ metadata.gz: 6e71f18ed659d830765786daba4513f7cedfef9fb645055cd01e95af8be066b3
4
+ data.tar.gz: c3b0624ab16f81e2aa7e4296a56a4967e88e75659eca20078ad662c0cc7d37ec
5
5
  SHA512:
6
- metadata.gz: cbae79e450983c1dd968b5f9959b4497758c32cc2c21a45ecea5b41dc1d7829fac2699d0a8cea635369d276eaec5b07ce8d7fa292674578ff62690823bc163fc
7
- data.tar.gz: df37746eee87f40792499e02421f82a2fc4afa4317e168bdb440f3bed1ba737c761469092098f99e2aa3fb163f50981e6b19a83a4859e91871ac8f046363f630
6
+ metadata.gz: b94b8a054612a71dc72078a0b62abf5db8a9bb305515ac75e2baeb39ab12d188eea4c168f3e774b3beebb608c821e808e2c24164a68fbdaebf894c7a566ec69e
7
+ data.tar.gz: f46b3769bc15ac507442548b1b9e810d0e70ae68a4a89eb29732c1c1b325d307eed593ab7ee49a78d6296bf69440ceb221ddb1e25e4b3237e5a723595c2903ed
data/README.md CHANGED
@@ -432,6 +432,10 @@ Delayed::Worker.read_ahead = 5
432
432
 
433
433
  # If a worker finds no jobs, it will sleep this number of seconds in between attempts:
434
434
  Delayed::Worker.sleep_delay = 5
435
+
436
+ # Until version 1.0, the worker will not sleep at all between attemps if it finds jobs.
437
+ # This can be configured by setting the minimum reserve interval:
438
+ Delayed::Worker.min_reserve_interval = 0.5 # seconds
435
439
  ```
436
440
 
437
441
  If a job fails, it will be rerun up to 25 times (with an exponential back-off). Jobs will also
@@ -21,7 +21,7 @@ module Delayed
21
21
  def on_exit!; end
22
22
 
23
23
  def interruptable_sleep(seconds)
24
- pipe[0].wait_readable(seconds)
24
+ pipe[0].wait_readable(seconds) if seconds.positive?
25
25
  end
26
26
 
27
27
  def stop
@@ -12,6 +12,7 @@ module Delayed
12
12
  include Runnable
13
13
 
14
14
  cattr_accessor :sleep_delay, instance_writer: false, default: 5
15
+ cattr_accessor :min_reserve_interval, instance_writer: false, default: 0
15
16
  cattr_accessor :max_attempts, instance_writer: false, default: 25
16
17
  cattr_accessor :max_claims, instance_writer: false, default: 5
17
18
  cattr_accessor :max_run_time, instance_writer: false, default: 20.minutes
@@ -92,6 +93,7 @@ module Delayed
92
93
  total = 0
93
94
 
94
95
  while total < num
96
+ start = clock_time
95
97
  jobs = reserve_jobs
96
98
  break if jobs.empty?
97
99
 
@@ -107,6 +109,9 @@ module Delayed
107
109
  pool.wait_for_termination
108
110
 
109
111
  break if stop? # leave if we're exiting
112
+
113
+ elapsed = clock_time - start
114
+ interruptable_sleep(self.class.min_reserve_interval - elapsed)
110
115
  end
111
116
 
112
117
  [success.value, total - success.value]
@@ -227,5 +232,9 @@ module Delayed
227
232
  def reload!
228
233
  Rails.application.reloader.reload! if defined?(Rails.application.reloader) && Rails.application.reloader.check!
229
234
  end
235
+
236
+ def clock_time
237
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
238
+ end
230
239
  end
231
240
  end
@@ -64,7 +64,7 @@ describe 'rake' do
64
64
  .to change { Delayed::Worker.min_priority }.from(nil).to(6)
65
65
  .and change { Delayed::Worker.max_priority }.from(nil).to(8)
66
66
  .and change { Delayed::Worker.queues }.from([]).to(%w(foo bar))
67
- .and change { Delayed::Worker.sleep_delay }.from(5).to(1)
67
+ .and change { Delayed::Worker.sleep_delay }.from(TEST_SLEEP_DELAY).to(1)
68
68
  .and change { Delayed::Worker.read_ahead }.from(5).to(3)
69
69
  .and change { Delayed::Worker.max_claims }.from(5).to(3)
70
70
  end
@@ -96,7 +96,7 @@ describe 'rake' do
96
96
  .to change { Delayed::Worker.min_priority }.from(nil).to(6)
97
97
  .and change { Delayed::Worker.max_priority }.from(nil).to(8)
98
98
  .and change { Delayed::Worker.queues }.from([]).to(%w(foo))
99
- .and change { Delayed::Worker.sleep_delay }.from(5).to(1)
99
+ .and change { Delayed::Worker.sleep_delay }.from(TEST_SLEEP_DELAY).to(1)
100
100
  .and change { Delayed::Worker.read_ahead }.from(5).to(3)
101
101
  .and change { Delayed::Worker.max_claims }.from(5).to(3)
102
102
  end
data/spec/helper.rb CHANGED
@@ -97,6 +97,11 @@ class SingletonClass
97
97
  include Singleton
98
98
  end
99
99
 
100
+ # Negative values are treated as sleep(0),
101
+ # so we can use different values to test the sleep behavior:
102
+ TEST_MIN_RESERVE_INTERVAL = -10
103
+ TEST_SLEEP_DELAY = -100
104
+
100
105
  RSpec.configure do |config|
101
106
  config.around(:each) do |example|
102
107
  aj_priority_was = ActiveJob::Base.priority
@@ -113,6 +118,14 @@ RSpec.configure do |config|
113
118
  queues_was = Delayed::Worker.queues
114
119
  read_ahead_was = Delayed::Worker.read_ahead
115
120
  sleep_delay_was = Delayed::Worker.sleep_delay
121
+ min_reserve_interval_was = Delayed::Worker.min_reserve_interval
122
+
123
+ if Gem.loaded_specs['delayed'].version >= Gem::Version.new('1.0') && min_reserve_interval_was.zero?
124
+ raise "Min reserve interval should be nonzero in v1.0 release"
125
+ end
126
+
127
+ Delayed::Worker.sleep_delay = TEST_SLEEP_DELAY
128
+ Delayed::Worker.min_reserve_interval = TEST_MIN_RESERVE_INTERVAL
116
129
 
117
130
  example.run
118
131
  ensure
@@ -130,6 +143,7 @@ RSpec.configure do |config|
130
143
  Delayed::Worker.queues = queues_was
131
144
  Delayed::Worker.read_ahead = read_ahead_was
132
145
  Delayed::Worker.sleep_delay = sleep_delay_was
146
+ Delayed::Worker.min_reserve_interval = min_reserve_interval_was
133
147
 
134
148
  Delayed::Job.delete_all
135
149
  end
data/spec/worker_spec.rb CHANGED
@@ -1,10 +1,6 @@
1
1
  require 'helper'
2
2
 
3
3
  describe Delayed::Worker do
4
- before do
5
- described_class.sleep_delay = 0
6
- end
7
-
8
4
  describe 'start' do
9
5
  it 'runs the :execute lifecycle hook' do
10
6
  performances = []
@@ -32,62 +28,74 @@ describe Delayed::Worker do
32
28
  allow(subject).to receive(:interruptable_sleep).and_call_original
33
29
  end
34
30
 
35
- context 'when there are no jobs' do
36
- before do
37
- allow(Delayed::Job).to receive(:reserve).and_return([])
38
- end
31
+ around do |example|
32
+ max_claims_was = described_class.max_claims
33
+ described_class.max_claims = max_claims
34
+ example.run
35
+ ensure
36
+ described_class.max_claims = max_claims_was
37
+ end
39
38
 
40
- it 'does not log and then sleeps' do
39
+ before do
40
+ allow(Delayed::Job).to receive(:reserve).and_return((0...jobs_returned).map { job }, [])
41
+ end
42
+
43
+ let(:max_claims) { 1 }
44
+ let(:jobs_returned) { 1 }
45
+ let(:job) do
46
+ instance_double(
47
+ Delayed::Job,
48
+ id: 123,
49
+ max_run_time: 10,
50
+ name: 'MyJob',
51
+ run_at: Delayed::Job.db_time_now,
52
+ created_at: Delayed::Job.db_time_now,
53
+ priority: Delayed::Priority.interactive,
54
+ queue: 'testqueue',
55
+ attempts: 0,
56
+ invoke_job: true,
57
+ destroy: true,
58
+ )
59
+ end
60
+
61
+ it 'logs the count and sleeps only within the loop' do
62
+ subject.run!
63
+ expect(Delayed.logger).to have_received(:info).with(/1 jobs processed/)
64
+ expect(subject).to have_received(:interruptable_sleep).once.with(a_value_within(1).of(TEST_MIN_RESERVE_INTERVAL))
65
+ expect(subject).not_to have_received(:interruptable_sleep).with(TEST_SLEEP_DELAY)
66
+ end
67
+
68
+ context 'when no jobs are returned' do
69
+ let(:jobs_returned) { 0 }
70
+
71
+ it 'does not log and then sleeps only outside of the loop' do
41
72
  subject.run!
42
73
  expect(Delayed.logger).not_to have_received(:info)
43
- expect(subject).to have_received(:interruptable_sleep)
74
+ expect(subject).to have_received(:interruptable_sleep).with(TEST_SLEEP_DELAY)
44
75
  end
45
76
  end
46
77
 
47
- context 'when there is a job worked off' do
48
- around do |example|
49
- max_claims_was = described_class.max_claims
50
- described_class.max_claims = max_claims
51
- example.run
52
- ensure
53
- described_class.max_claims = max_claims_was
54
- end
55
-
56
- before do
57
- allow(Delayed::Job).to receive(:reserve).and_return([job], [])
58
- end
59
-
60
- let(:max_claims) { 1 }
61
- let(:job) do
62
- instance_double(
63
- Delayed::Job,
64
- id: 123,
65
- max_run_time: 10,
66
- name: 'MyJob',
67
- run_at: Delayed::Job.db_time_now,
68
- created_at: Delayed::Job.db_time_now,
69
- priority: Delayed::Priority.interactive,
70
- queue: 'testqueue',
71
- attempts: 0,
72
- invoke_job: true,
73
- destroy: true,
74
- )
75
- end
78
+ context 'when max_claims is 3 and 3 jobs are returned' do
79
+ let(:max_claims) { 3 }
80
+ let(:jobs_returned) { 3 }
76
81
 
77
- it 'logs the count and does not sleep' do
82
+ it 'logs the count and sleeps only in the loop' do
78
83
  subject.run!
79
- expect(Delayed.logger).to have_received(:info).with(/1 jobs processed/)
80
- expect(subject).not_to have_received(:interruptable_sleep)
84
+ expect(Delayed.logger).to have_received(:info).with(/3 jobs processed/)
85
+ expect(subject).to have_received(:interruptable_sleep).once.with(a_value_within(1).of(TEST_MIN_RESERVE_INTERVAL))
86
+ expect(subject).not_to have_received(:interruptable_sleep).with(TEST_SLEEP_DELAY)
81
87
  end
88
+ end
82
89
 
83
- context 'when max_claims is 2' do
84
- let(:max_claims) { 2 }
90
+ context 'when max_claims is 3 and 2 jobs are returned' do
91
+ let(:max_claims) { 3 }
92
+ let(:jobs_returned) { 2 }
85
93
 
86
- it 'logs the count and sleeps' do
87
- subject.run!
88
- expect(Delayed.logger).to have_received(:info).with(/1 jobs processed/)
89
- expect(subject).to have_received(:interruptable_sleep)
90
- end
94
+ it 'logs the count and sleeps both in the loop and outside of the loop' do
95
+ subject.run!
96
+ expect(Delayed.logger).to have_received(:info).with(/2 jobs processed/)
97
+ expect(subject).to have_received(:interruptable_sleep).once.with(a_value_within(1).of(TEST_MIN_RESERVE_INTERVAL))
98
+ expect(subject).to have_received(:interruptable_sleep).once.with(TEST_SLEEP_DELAY)
91
99
  end
92
100
  end
93
101
  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.5.5
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
@@ -19,7 +19,7 @@ authors:
19
19
  autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
- date: 2024-08-13 00:00:00.000000000 Z
22
+ date: 2024-12-18 00:00:00.000000000 Z
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: activerecord