resque-scheduler 5.1.0 → 5.1.1

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: 6aa6e1f1a8fe48f091032409157797e48011e473fca30c8fd12d18d05517de49
4
- data.tar.gz: cbcc8d19930096797a1d028a9765b9c7c0b65ae023011ccec64cf8005420f183
3
+ metadata.gz: 7a49c095f83e23c0bb20e1dffe6038c64a50376d89a0123436eae4233a74e390
4
+ data.tar.gz: 80bd2fb3055d7904d0d62f47f3683c5c6a6f5c4d7236d7311b29ee7c6d2f1174
5
5
  SHA512:
6
- metadata.gz: a3842dbcedbb2768e715aef2355f11333cadfa101ccb5a1475dbda155005d494408e0554c027ba5cf72afcabc7dcd3778125b9f512680850c875efbccb94f64f
7
- data.tar.gz: 9623d1a81de5c0e1179e7be932ad6a19641dbcbc57c7b9034fc531160ae6e896374611d5d0f1dc64a710c27293cbc0e1db0eda9f6e5ad4c5ed8208398e20cdae
6
+ metadata.gz: c206ceb2414921369b7fd89800f95a8e3583226d709fd6d92effbfa69c1284711081cd46189b05aee1d14fdc3161f3d8fee0d7588c4e81a0a2cff6a791c0e415
7
+ data.tar.gz: f99d4d481f7ec3de91bef5a3b5ead66474e0f1df72a68bb705058de727ed448cd60cae39b901fd0b3edd4d02004fb87147e08a7b265517ca2b5109e194d7fb54
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  **ATTN**: This project uses [semantic versioning](http://semver.org/).
4
4
 
5
+ ## [5.1.1] - 2026-11-02
6
+ ### Fixed
7
+ * Enqueue batched delayed jobs outside the Redis transaction so a conflicted batch is no longer enqueued twice and enqueue hooks can use Redis by @neuromanskie in #850
8
+ * Skip due delayed items when not master instead of spinning on them by @neuromanskie in #852
9
+ * Load the web UI after Rails initialization to avoid a circular require warning by @neuromanskie in #854
10
+
5
11
  ## [5.1.0] - 2026-10-28
6
12
  ### Breaking Changes
7
13
  * Ruby requirement: `>= 3.0.0` → `>= 3.2.0` by @neuromanskie in #837
data/README.md CHANGED
@@ -135,7 +135,7 @@ environment variables:
135
135
  * `BACKGROUND` - [Run in the background](#running-in-the-background) if
136
136
  non-empty (via `Process.daemon`, if supported) (default `false`)
137
137
  * `DELAYED_REQUEUE_BATCH_SIZE` - Set the delayed job batch size if enabled (default `100`). If `<= 1`, this disables batching.
138
- * `DISABLE_DELAYED_REQUEUE_BATCHES` - Disable batched delayed job queuing (default `false`) - [See section below on consequences](#batched-delayed-job-and-resque-enqueue-hooks)
138
+ * `DISABLE_DELAYED_REQUEUE_BATCHES` - Disable batched delayed job queuing (default `false`)
139
139
  * `DYNAMIC_SCHEDULE` - Enables [dynamic scheduling](#dynamic-schedules)
140
140
  if non-empty (default `false`)
141
141
  * `RAILS_ENV` - Environment to use in procline (`$0`) (default empty)
@@ -784,35 +784,6 @@ This table explains the version requirements for rufus-scheduler
784
784
  | `~> 4.0` | `~> 3.0` |
785
785
  | `< 4.0` | `~> 2.0` |
786
786
 
787
- ##### Batched delayed job and resque enqueue hooks
788
-
789
- Batching delayed job queuing can speed up when per-second job counts grows,
790
- avoiding situations that may cause delayed enqueues to fall behind. This
791
- batching wraps enqueues in a `multi` pipeline, making far fewer roundtrips to
792
- the server.
793
-
794
- However, in `redis` gem `>= 4.0`, any operations to Redis within the `multi`
795
- block must use the multi handle so that the actions are captured. Resque's hooks
796
- do not currently have a way to pass this around, and so compatibility with other
797
- Resque plugins or hooks which access Redis at enqueue time is impacted with
798
- batch mode (A main class of plugins this affects are single runner locks which
799
- use redis for their locking mechanism). In these cases, you should consider
800
- disabling the batching by setting the `DISABLE_DELAYED_REQUEUE_BATCHES`
801
- environment variable to `true`.
802
-
803
- Detecting when this occurs can be tricky, you must watch for logs
804
- emitted by your `resque-scheduler` process such as:
805
-
806
- ```text
807
- Redis::CommandError: ERR
808
- MULTI calls can not be nested
809
- NoMethodError: undefined method nil? for <Redis::Future
810
- NoMethodError: undefined method `to_i' for <Redis::Future
811
- ```
812
-
813
- If you're in this situation, you will also see delayed jobs to not be enqueued
814
- (they will get dropped). Disabling batching is the workaround.
815
-
816
787
  ### Contributing
817
788
 
818
789
  See [CONTRIBUTING.md](CONTRIBUTING.md)
@@ -1,8 +1,10 @@
1
- require 'resque/scheduler/server'
2
-
3
1
  module Resque
4
2
  module Scheduler
5
3
  class Railtie < Rails::Railtie
4
+ config.after_initialize do
5
+ require 'resque/scheduler/server'
6
+ end
7
+
6
8
  rake_tasks do
7
9
  require 'resque/scheduler/tasks'
8
10
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Resque
4
4
  module Scheduler
5
- VERSION = '5.1.0'.freeze
5
+ VERSION = '5.1.1'.freeze
6
6
  end
7
7
  end
@@ -198,7 +198,7 @@ module Resque
198
198
  # at_time - Time to start scheduling items (default: now).
199
199
  def handle_delayed_items(at_time = nil)
200
200
  timestamp = Resque.next_delayed_timestamp(at_time)
201
- if timestamp
201
+ if timestamp && am_master
202
202
  procline 'Processing Delayed Items'
203
203
  until timestamp.nil?
204
204
  enqueue_delayed_items_for_timestamp(timestamp)
@@ -235,11 +235,10 @@ module Resque
235
235
  actual_batch_size = 0
236
236
 
237
237
  handle_shutdown do
238
- # Continually check that it is still the master
239
238
  if am_master
240
239
  if batch_delayed_items?
241
240
  actual_batch_size = enqueue_items_in_batch_for_timestamp(timestamp, batch_size)
242
- log "queued batch of #{actual_batch_size} jobs" if actual_batch_size != -1
241
+ log "queued batch of #{actual_batch_size} jobs"
243
242
  else
244
243
  item = enqueue_next_item(timestamp)
245
244
  actual_batch_size = item.nil? ? 0 : 1
@@ -251,8 +250,6 @@ module Resque
251
250
 
252
251
  # continue processing until there are no more items in this
253
252
  # timestamp. If we don't have a full batch, this is the last one.
254
- # This also breaks us in the event of a redis transaction failure
255
- # i.e. enqueue_items_in_batch_for_timestamp returned -1
256
253
  break if actual_batch_size < batch_size
257
254
  end
258
255
 
@@ -266,45 +263,32 @@ module Resque
266
263
  def enqueue_items_in_batch_for_timestamp(timestamp, batch_size)
267
264
  timestamp_bucket_key = timestamp_key(timestamp)
268
265
 
269
- encoded_jobs_to_requeue = Resque.redis.lrange(timestamp_bucket_key, 0, batch_size - 1)
270
-
271
- # Watch is used to ensure that the timestamp bucket we are operating on
272
- # is not altered by any other clients between the watch call and when we call exec
273
- # (to execute the multi block). We should error catch on the redis.exec return value
274
- # as that will indicate if the entire transaction was aborted or not. Though we should
275
- # be safe as our ltrim is inside the multi block and therefore also would have been
276
- # aborted. So nothing would have been queued, but also nothing lost from the bucket.
277
- watch_result = Resque.redis.watch(timestamp_bucket_key) do
278
- Resque.redis.multi do |pipeline|
279
- encoded_jobs_to_requeue.each do |encoded_job|
280
- pipeline.srem("timestamps:#{encoded_job}", timestamp_bucket_key)
281
-
282
- decoded_job = Resque.decode(encoded_job)
283
- enqueue(decoded_job, :delayed)
284
- end
266
+ return 0 unless (encoded_jobs = take_delayed_batch(timestamp_bucket_key, batch_size))
285
267
 
286
- pipeline.ltrim(timestamp_bucket_key, batch_size, -1)
287
- end
268
+ encoded_jobs.each do |encoded_job|
269
+ enqueue(Resque.decode(encoded_job), :delayed)
288
270
  end
289
271
 
290
- # Did the multi block successfully remove from this timestamp and enqueue the jobs?
291
- success = !watch_result.nil?
292
-
293
- # If this was the last batch in this timestamp bucket, clean up
294
- if success && encoded_jobs_to_requeue.count < batch_size
272
+ if encoded_jobs.count < batch_size
295
273
  Resque.clean_up_timestamp(timestamp_bucket_key, timestamp)
296
274
  end
297
275
 
298
- unless success
299
- # Our batched transaction failed in Redis due to the timestamp_bucket_key value
300
- # being modified while we built our multi block. We return -1 to ensure we break
301
- # out of the loop iterating on this timestamp so it can be re-processed via the
302
- # loop in handle_delayed_items.
303
- return -1
304
- end
276
+ encoded_jobs.count
277
+ end
305
278
 
306
- # will return 0 if none were left to batch
307
- encoded_jobs_to_requeue.count
279
+ # Returns nil if the timestamp bucket changed before the batch was taken.
280
+ def take_delayed_batch(timestamp_bucket_key, batch_size)
281
+ Resque.redis.watch(timestamp_bucket_key) do
282
+ encoded_jobs = Resque.redis.lrange(timestamp_bucket_key, 0, batch_size - 1)
283
+ taken = Resque.redis.multi do |transaction|
284
+ encoded_jobs.each do |encoded_job|
285
+ transaction.srem("timestamps:#{encoded_job}", [timestamp_bucket_key])
286
+ end
287
+ transaction.ltrim(timestamp_bucket_key, batch_size, -1)
288
+ end
289
+
290
+ encoded_jobs if taken
291
+ end
308
292
  end
309
293
 
310
294
  # Enqueues a job like enqueue_from_config, but hands errors to the failure
@@ -52,6 +52,7 @@ Gem::Specification.new do |spec|
52
52
  spec.add_development_dependency 'ostruct'
53
53
  spec.add_development_dependency 'pry'
54
54
  spec.add_development_dependency 'rack-test'
55
+ spec.add_development_dependency 'railties'
55
56
  spec.add_development_dependency 'rake'
56
57
  spec.add_development_dependency 'simplecov'
57
58
  spec.add_development_dependency 'test-unit'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben VandenBos
@@ -140,6 +140,20 @@ dependencies:
140
140
  - - ">="
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: railties
145
+ requirement: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
143
157
  - !ruby/object:Gem::Dependency
144
158
  name: rake
145
159
  requirement: !ruby/object:Gem::Requirement