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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -30
- data/lib/resque/scheduler/railtie.rb +4 -2
- data/lib/resque/scheduler/version.rb +1 -1
- data/lib/resque/scheduler.rb +21 -37
- data/resque-scheduler.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a49c095f83e23c0bb20e1dffe6038c64a50376d89a0123436eae4233a74e390
|
|
4
|
+
data.tar.gz: 80bd2fb3055d7904d0d62f47f3683c5c6a6f5c4d7236d7311b29ee7c6d2f1174
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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`)
|
|
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)
|
data/lib/resque/scheduler.rb
CHANGED
|
@@ -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"
|
|
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
|
-
|
|
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
|
-
|
|
287
|
-
|
|
268
|
+
encoded_jobs.each do |encoded_job|
|
|
269
|
+
enqueue(Resque.decode(encoded_job), :delayed)
|
|
288
270
|
end
|
|
289
271
|
|
|
290
|
-
|
|
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
|
-
|
|
299
|
-
|
|
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
|
-
|
|
307
|
-
|
|
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
|
data/resque-scheduler.gemspec
CHANGED
|
@@ -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.
|
|
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
|