resque-scheduler 4.4.0 → 4.11.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.
@@ -10,13 +10,13 @@ module Resque
10
10
  end
11
11
 
12
12
  # For all signals, set the shutdown flag and wait for current
13
- # poll/enqueing to finish (should be almost instant). In the
13
+ # poll/enqueuing to finish (should be almost instant). In the
14
14
  # case of sleeping, exit immediately.
15
15
  def register_signal_handlers
16
16
  (Signal.list.keys & %w(INT TERM USR1 USR2 QUIT)).each do |sig|
17
17
  trap(sig) do
18
18
  signal_queue << sig
19
- # break sleep in the primary scheduler thread, alowing
19
+ # break sleep in the primary scheduler thread, allowing
20
20
  # the signal queue to get processed as soon as possible.
21
21
  @th.wakeup if @th && @th.alive?
22
22
  end
@@ -4,7 +4,7 @@ module Resque
4
4
  module Scheduler
5
5
  class Util
6
6
  # In order to upgrade to resque(1.25) which has deprecated following
7
- # methods, we just added these usefull helpers back to use in Resque
7
+ # methods, we just added these useful helpers back to use in Resque
8
8
  # Scheduler. refer to:
9
9
  # https://github.com/resque/resque-scheduler/pull/273
10
10
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Resque
4
4
  module Scheduler
5
- VERSION = '4.4.0'.freeze
5
+ VERSION = '4.11.0'.freeze
6
6
  end
7
7
  end
@@ -1,5 +1,6 @@
1
1
  # vim:fileencoding=utf-8
2
2
 
3
+ require 'redis/errors'
3
4
  require 'rufus/scheduler'
4
5
  require_relative 'scheduler/configuration'
5
6
  require_relative 'scheduler/locking'
@@ -205,16 +206,80 @@ module Resque
205
206
 
206
207
  # Enqueues all delayed jobs for a timestamp
207
208
  def enqueue_delayed_items_for_timestamp(timestamp)
208
- item = nil
209
+ count = 0
210
+ batch_size = delayed_requeue_batch_size
211
+ actual_batch_size = nil
212
+
213
+ log "Processing delayed items for timestamp #{timestamp}, in batches of #{batch_size}"
214
+
209
215
  loop do
210
216
  handle_shutdown do
211
217
  # Continually check that it is still the master
212
- item = enqueue_next_item(timestamp) if am_master
218
+ if am_master
219
+ actual_batch_size = enqueue_items_in_batch_for_timestamp(timestamp,
220
+ batch_size)
221
+ end
213
222
  end
214
- # continue processing until there are no more ready items in this
215
- # timestamp
216
- break if item.nil?
223
+
224
+ count += actual_batch_size
225
+ log "queued #{count} jobs" if actual_batch_size != -1
226
+
227
+ # continue processing until there are no more items in this
228
+ # timestamp. If we don't have a full batch, this is the last one.
229
+ # This also breaks us in the event of a redis transaction failure
230
+ # i.e. enqueue_items_in_batch_for_timestamp returned -1
231
+ break if actual_batch_size < batch_size
217
232
  end
233
+
234
+ log "finished queueing #{count} total jobs for timestamp #{timestamp}" if count != -1
235
+ end
236
+
237
+ def timestamp_key(timestamp)
238
+ "delayed:#{timestamp.to_i}"
239
+ end
240
+
241
+ def enqueue_items_in_batch_for_timestamp(timestamp, batch_size)
242
+ timestamp_bucket_key = timestamp_key(timestamp)
243
+
244
+ encoded_jobs_to_requeue = Resque.redis.lrange(timestamp_bucket_key, 0, batch_size - 1)
245
+
246
+ # Watch is used to ensure that the timestamp bucket we are operating on
247
+ # is not altered by any other clients between the watch call and when we call exec
248
+ # (to execute the multi block). We should error catch on the redis.exec return value
249
+ # as that will indicate if the entire transaction was aborted or not. Though we should
250
+ # be safe as our ltrim is inside the multi block and therefore also would have been
251
+ # aborted. So nothing would have been queued, but also nothing lost from the bucket.
252
+ watch_result = Resque.redis.watch(timestamp_bucket_key) do
253
+ Resque.redis.multi do |pipeline|
254
+ encoded_jobs_to_requeue.each do |encoded_job|
255
+ pipeline.srem("timestamps:#{encoded_job}", timestamp_bucket_key)
256
+
257
+ decoded_job = Resque.decode(encoded_job)
258
+ enqueue(decoded_job)
259
+ end
260
+
261
+ pipeline.ltrim(timestamp_bucket_key, batch_size, -1)
262
+ end
263
+ end
264
+
265
+ # Did the multi block successfully remove from this timestamp and enqueue the jobs?
266
+ success = !watch_result.nil?
267
+
268
+ # If this was the last batch in this timestamp bucket, clean up
269
+ if success && encoded_jobs_to_requeue.count < batch_size
270
+ Resque.clean_up_timestamp(timestamp_bucket_key, timestamp)
271
+ end
272
+
273
+ unless success
274
+ # Our batched transaction failed in Redis due to the timestamp_bucket_key value
275
+ # being modified while we built our multi block. We return -1 to ensure we break
276
+ # out of the loop iterating on this timestamp so it can be re-processed via the
277
+ # loop in handle_delayed_items.
278
+ return -1
279
+ end
280
+
281
+ # will return 0 if none were left to batch
282
+ encoded_jobs_to_requeue.count
218
283
  end
219
284
 
220
285
  def enqueue(config)
@@ -250,7 +315,7 @@ module Resque
250
315
  if job_klass && job_klass != 'Resque::Job'
251
316
  # The custom job class API must offer a static "scheduled" method. If
252
317
  # the custom job class can not be constantized (via a requeue call
253
- # from the web perhaps), fall back to enqueing normally via
318
+ # from the web perhaps), fall back to enqueuing normally via
254
319
  # Resque::Job.create.
255
320
  begin
256
321
  Resque::Scheduler::Util.constantize(job_klass).scheduled(
@@ -266,17 +331,16 @@ module Resque
266
331
  # for non-existent classes (for example: running scheduler in
267
332
  # one app that schedules for another.
268
333
  if Class === klass
269
- Resque::Scheduler::Plugin.run_before_delayed_enqueue_hooks(
270
- klass, *params
271
- )
272
-
273
- # If the class is a custom job class, call self#scheduled on it.
274
- # This allows you to do things like Resque.enqueue_at(timestamp,
275
- # CustomJobClass). Otherwise, pass off to Resque.
276
- if klass.respond_to?(:scheduled)
277
- klass.scheduled(queue, klass_name, *params)
278
- else
279
- Resque.enqueue_to(queue, klass, *params)
334
+ Resque::Scheduler::Plugin.process_schedule_hooks(klass, *params) do
335
+ Resque::Scheduler::Plugin.run_before_delayed_enqueue_hooks(klass, *params)
336
+ # If the class is a custom job class, call self#scheduled on it.
337
+ # This allows you to do things like Resque.enqueue_at(timestamp,
338
+ # CustomJobClass). Otherwise, pass off to Resque.
339
+ if klass.respond_to?(:scheduled)
340
+ klass.scheduled(queue, klass_name, *params)
341
+ else
342
+ Resque.enqueue_to(queue, klass, *params)
343
+ end
280
344
  end
281
345
  else
282
346
  # This will not run the before_hooks in rescue, but will at least
@@ -376,7 +440,6 @@ module Resque
376
440
 
377
441
  def stop_rufus_scheduler
378
442
  rufus_scheduler.shutdown(:wait)
379
- rufus_scheduler.join
380
443
  end
381
444
 
382
445
  def before_shutdown
@@ -11,12 +11,16 @@ Gem::Specification.new do |spec|
11
11
  Simon Eskildsen
12
12
  Ryan Biesemeyer
13
13
  Dan Buch
14
+ Michael Bianco
15
+ Patrick Tulskie
14
16
  EOF
15
17
  spec.email = %w(
16
18
  bvandenbos@gmail.com
17
19
  sirup@sirupsen.com
18
20
  ryan@yaauie.com
19
21
  dan@meatballhat.com
22
+ mike@mikebian.co
23
+ patricktulskie@gmail.com
20
24
  )
21
25
  spec.summary = 'Light weight job scheduling on top of Resque'
22
26
  spec.description = <<-DESCRIPTION
@@ -24,13 +28,16 @@ Gem::Specification.new do |spec|
24
28
  Adds methods enqueue_at/enqueue_in to schedule jobs in the future.
25
29
  Also supports queueing jobs on a fixed, cron-like schedule.
26
30
  DESCRIPTION
27
- spec.homepage = 'http://github.com/resque/resque-scheduler'
31
+ spec.homepage = 'https://github.com/resque/resque-scheduler'
28
32
  spec.license = 'MIT'
33
+ spec.metadata['rubygems_mfa_required'] = 'true'
34
+
35
+ spec.required_ruby_version = '>= 2.3.0'
29
36
 
30
37
  spec.files = `git ls-files -z`.split("\0").reject do |f|
31
38
  f.match(%r{^(test|spec|features|examples|bin|tasks)/}) ||
32
- f.match(/^(Vagrantfile|Gemfile\.lock|appveyor\.yml)/) ||
33
- f.match(/^\.(rubocop|simplecov|travis|vagrant|gitignore)/)
39
+ f.match(/^(Vagrantfile|Gemfile\.lock)/) ||
40
+ f.match(/^\.(rubocop|simplecov|vagrant|gitignore)/)
34
41
  end
35
42
  spec.bindir = 'exe'
36
43
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -38,7 +45,6 @@ Gem::Specification.new do |spec|
38
45
 
39
46
  spec.add_development_dependency 'bundler'
40
47
  spec.add_development_dependency 'json'
41
- spec.add_development_dependency 'kramdown'
42
48
  spec.add_development_dependency 'minitest'
43
49
  spec.add_development_dependency 'mocha'
44
50
  spec.add_development_dependency 'pry'
@@ -47,7 +53,7 @@ Gem::Specification.new do |spec|
47
53
  spec.add_development_dependency 'simplecov'
48
54
  spec.add_development_dependency 'test-unit'
49
55
  spec.add_development_dependency 'yard'
50
- spec.add_development_dependency 'tzinfo-data'
56
+ spec.add_development_dependency 'timecop'
51
57
 
52
58
  # We pin rubocop because new cops have a tendency to result in false-y
53
59
  # positives for new contributors, which is not a nice experience.
@@ -55,6 +61,8 @@ Gem::Specification.new do |spec|
55
61
 
56
62
  spec.add_runtime_dependency 'mono_logger', '~> 1.0'
57
63
  spec.add_runtime_dependency 'redis', '>= 3.3'
58
- spec.add_runtime_dependency 'resque', '>= 1.26'
59
- spec.add_runtime_dependency 'rufus-scheduler', '~> 3.2'
64
+ spec.add_runtime_dependency 'resque', '>= 1.27'
65
+ # rufus-scheduler v3.7 causes a failure in test/multi_process_test.rb
66
+ # rufus-scheduler v3.3 is missing a to_local method which fails tests
67
+ spec.add_runtime_dependency 'rufus-scheduler', '~> 3.2', '!= 3.3'
60
68
  end
metadata CHANGED
@@ -1,17 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0
4
+ version: 4.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben VandenBos
8
8
  - Simon Eskildsen
9
9
  - Ryan Biesemeyer
10
10
  - Dan Buch
11
+ - Michael Bianco
12
+ - Patrick Tulskie
11
13
  autorequire:
12
14
  bindir: exe
13
15
  cert_chain: []
14
- date: 2019-04-15 00:00:00.000000000 Z
16
+ date: 2024-12-30 00:00:00.000000000 Z
15
17
  dependencies:
16
18
  - !ruby/object:Gem::Dependency
17
19
  name: bundler
@@ -41,20 +43,6 @@ dependencies:
41
43
  - - ">="
42
44
  - !ruby/object:Gem::Version
43
45
  version: '0'
44
- - !ruby/object:Gem::Dependency
45
- name: kramdown
46
- requirement: !ruby/object:Gem::Requirement
47
- requirements:
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: '0'
51
- type: :development
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: '0'
58
46
  - !ruby/object:Gem::Dependency
59
47
  name: minitest
60
48
  requirement: !ruby/object:Gem::Requirement
@@ -168,7 +156,7 @@ dependencies:
168
156
  - !ruby/object:Gem::Version
169
157
  version: '0'
170
158
  - !ruby/object:Gem::Dependency
171
- name: tzinfo-data
159
+ name: timecop
172
160
  requirement: !ruby/object:Gem::Requirement
173
161
  requirements:
174
162
  - - ">="
@@ -229,14 +217,14 @@ dependencies:
229
217
  requirements:
230
218
  - - ">="
231
219
  - !ruby/object:Gem::Version
232
- version: '1.26'
220
+ version: '1.27'
233
221
  type: :runtime
234
222
  prerelease: false
235
223
  version_requirements: !ruby/object:Gem::Requirement
236
224
  requirements:
237
225
  - - ">="
238
226
  - !ruby/object:Gem::Version
239
- version: '1.26'
227
+ version: '1.27'
240
228
  - !ruby/object:Gem::Dependency
241
229
  name: rufus-scheduler
242
230
  requirement: !ruby/object:Gem::Requirement
@@ -244,6 +232,9 @@ dependencies:
244
232
  - - "~>"
245
233
  - !ruby/object:Gem::Version
246
234
  version: '3.2'
235
+ - - "!="
236
+ - !ruby/object:Gem::Version
237
+ version: '3.3'
247
238
  type: :runtime
248
239
  prerelease: false
249
240
  version_requirements: !ruby/object:Gem::Requirement
@@ -251,6 +242,9 @@ dependencies:
251
242
  - - "~>"
252
243
  - !ruby/object:Gem::Version
253
244
  version: '3.2'
245
+ - - "!="
246
+ - !ruby/object:Gem::Version
247
+ version: '3.3'
254
248
  description: |2
255
249
  Light weight job scheduling on top of Resque.
256
250
  Adds methods enqueue_at/enqueue_in to schedule jobs in the future.
@@ -260,11 +254,18 @@ email:
260
254
  - sirup@sirupsen.com
261
255
  - ryan@yaauie.com
262
256
  - dan@meatballhat.com
257
+ - mike@mikebian.co
258
+ - patricktulskie@gmail.com
263
259
  executables:
264
260
  - resque-scheduler
265
261
  extensions: []
266
262
  extra_rdoc_files: []
267
263
  files:
264
+ - ".github/dependabot.yml"
265
+ - ".github/funding.yml"
266
+ - ".github/workflows/codeql-analysis.yml"
267
+ - ".github/workflows/rubocop.yml"
268
+ - ".github/workflows/ruby.yml"
268
269
  - AUTHORS.md
269
270
  - CHANGELOG.md
270
271
  - CODE_OF_CONDUCT.md
@@ -303,10 +304,11 @@ files:
303
304
  - lib/resque/scheduler/util.rb
304
305
  - lib/resque/scheduler/version.rb
305
306
  - resque-scheduler.gemspec
306
- homepage: http://github.com/resque/resque-scheduler
307
+ homepage: https://github.com/resque/resque-scheduler
307
308
  licenses:
308
309
  - MIT
309
- metadata: {}
310
+ metadata:
311
+ rubygems_mfa_required: 'true'
310
312
  post_install_message:
311
313
  rdoc_options: []
312
314
  require_paths:
@@ -315,14 +317,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
315
317
  requirements:
316
318
  - - ">="
317
319
  - !ruby/object:Gem::Version
318
- version: '0'
320
+ version: 2.3.0
319
321
  required_rubygems_version: !ruby/object:Gem::Requirement
320
322
  requirements:
321
323
  - - ">="
322
324
  - !ruby/object:Gem::Version
323
325
  version: '0'
324
326
  requirements: []
325
- rubygems_version: 3.0.3
327
+ rubygems_version: 3.0.3.1
326
328
  signing_key:
327
329
  specification_version: 4
328
330
  summary: Light weight job scheduling on top of Resque