sidekiq 6.2.2 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +37 -1
- data/README.md +2 -2
- data/lib/sidekiq/api.rb +1 -0
- data/lib/sidekiq/cli.rb +10 -2
- data/lib/sidekiq/client.rb +2 -2
- data/lib/sidekiq/fetch.rb +4 -3
- data/lib/sidekiq/job.rb +8 -3
- data/lib/sidekiq/launcher.rb +5 -1
- data/lib/sidekiq/middleware/current_attributes.rb +48 -0
- data/lib/sidekiq/rails.rb +11 -0
- data/lib/sidekiq/redis_connection.rb +4 -6
- data/lib/sidekiq/scheduled.rb +33 -14
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +2 -2
- data/lib/sidekiq/web/helpers.rb +1 -12
- data/lib/sidekiq/worker.rb +72 -5
- data/lib/sidekiq.rb +3 -1
- data/sidekiq.gemspec +1 -1
- data/web/assets/javascripts/application.js +82 -61
- data/web/assets/javascripts/dashboard.js +51 -51
- data/web/assets/stylesheets/application-dark.css +7 -7
- data/web/assets/stylesheets/application-rtl.css +0 -4
- data/web/assets/stylesheets/application.css +7 -103
- data/web/locales/en.yml +1 -1
- data/web/views/_footer.erb +1 -1
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/dashboard.erb +8 -8
- data/web/views/layout.erb +1 -1
- data/web/views/queue.erb +10 -10
- data/web/views/queues.erb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b72b92d3d281aaea2b4781cb7743d95a8c7f42708526383bf85fbed420b4b82c
|
4
|
+
data.tar.gz: 9546107658b47c8f68497730e2ee6689881c1388ba96db3f2415b0fda7b7f668
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78f0af1f4ed41c5b4ad01636d9808d409d1cedc0bc6146be278412e87f9d826fad2cec9c89b31acbc6da9bab59bff44e826418991b10ce27b34631bcc3a00cf2
|
7
|
+
data.tar.gz: a586b9ec613cf3da47ecb77eb4e0f5d6e497f234369d958cdfa3d8c8c7418806383e022a9b08db4c3b5d08a1c2aac3aaecdf851744234f4c42055e1a7a6ebf6c
|
data/Changes.md
CHANGED
@@ -1,6 +1,42 @@
|
|
1
1
|
# Sidekiq Changes
|
2
2
|
|
3
|
-
[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/
|
3
|
+
[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/main/Ent-Changes.md)
|
4
|
+
|
5
|
+
HEAD
|
6
|
+
---------
|
7
|
+
|
8
|
+
- **BREAK**: The Web UI has been refactored to remove jQuery. Any UI extensions
|
9
|
+
which use jQuery will break.
|
10
|
+
- **FEATURE**: Sidekiq.logger has been enhanced so any `Rails.logger`
|
11
|
+
output in jobs now shows up in the Sidekiq console. Remove any logger
|
12
|
+
hacks in your initializer and see if it Just Works™ now. [#5021]
|
13
|
+
- **FEATURE**: Add `Sidekiq::Job` alias for `Sidekiq::Worker`, to better
|
14
|
+
reflect industry standard terminology. You can now do this:
|
15
|
+
```ruby
|
16
|
+
class MyJob
|
17
|
+
include Sidekiq::Job
|
18
|
+
sidekiq_options ...
|
19
|
+
def perform(args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
```
|
23
|
+
- **FEATURE**: Support for serializing ActiveSupport::CurrentAttributes into each job. [#4982]
|
24
|
+
```ruby
|
25
|
+
# config/initializers/sidekiq.rb
|
26
|
+
require "sidekiq/middleware/current_attributes"
|
27
|
+
Sidekiq::CurrentAttributes.persist(Myapp::Current) # Your AS::CurrentAttributes singleton
|
28
|
+
```
|
29
|
+
- **FEATURE**: Add `Sidekiq::Worker.perform_bulk` for enqueuing jobs in bulk,
|
30
|
+
similar to `Sidekiq::Client.push_bulk` [#5042]
|
31
|
+
```ruby
|
32
|
+
MyJob.perform_bulk([[1], [2], [3]])
|
33
|
+
```
|
34
|
+
- Implement `queue_as`, `wait` and `wait_until` for ActiveJob compatibility [#5003]
|
35
|
+
- Scheduler now uses Lua to reduce Redis load and network roundtrips [#5044]
|
36
|
+
- Retry Redis operation if we get an `UNBLOCKED` Redis error [#4985]
|
37
|
+
- Run existing signal traps, if any, before running Sidekiq's trap [#4991]
|
38
|
+
- Fix fetch bug when using weighted queues which caused Sidekiq to stop
|
39
|
+
processing queues randomly [#5031]
|
4
40
|
|
5
41
|
6.2.2
|
6
42
|
---------
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ See the [Getting Started wiki page](https://github.com/mperham/sidekiq/wiki/Gett
|
|
46
46
|
You can watch [this Youtube playlist](https://www.youtube.com/playlist?list=PLjeHh2LSCFrWGT5uVjUuFKAcrcj5kSai1) to learn all about
|
47
47
|
Sidekiq and see its features in action. Here's the Web UI:
|
48
48
|
|
49
|
-
![Web UI](https://github.com/mperham/sidekiq/raw/
|
49
|
+
![Web UI](https://github.com/mperham/sidekiq/raw/main/examples/web-ui.png)
|
50
50
|
|
51
51
|
|
52
52
|
Want to Upgrade?
|
@@ -84,7 +84,7 @@ See the [Sidekiq support page](https://sidekiq.org/support.html) for details.
|
|
84
84
|
License
|
85
85
|
-----------------
|
86
86
|
|
87
|
-
Please see [LICENSE](https://github.com/mperham/sidekiq/blob/
|
87
|
+
Please see [LICENSE](https://github.com/mperham/sidekiq/blob/main/LICENSE) for licensing details.
|
88
88
|
|
89
89
|
|
90
90
|
Author
|
data/lib/sidekiq/api.rb
CHANGED
data/lib/sidekiq/cli.rb
CHANGED
@@ -46,7 +46,15 @@ module Sidekiq
|
|
46
46
|
# USR1 and USR2 don't work on the JVM
|
47
47
|
sigs << "USR2" if Sidekiq.pro? && !jruby?
|
48
48
|
sigs.each do |sig|
|
49
|
-
trap
|
49
|
+
old_handler = Signal.trap(sig) do
|
50
|
+
if old_handler.respond_to?(:call)
|
51
|
+
begin
|
52
|
+
old_handler.call
|
53
|
+
rescue Exception => exc
|
54
|
+
# signal handlers can't use Logger so puts only
|
55
|
+
puts ["Error in #{sig} handler", exc].inspect
|
56
|
+
end
|
57
|
+
end
|
50
58
|
self_write.puts(sig)
|
51
59
|
end
|
52
60
|
rescue ArgumentError
|
@@ -396,7 +404,7 @@ module Sidekiq
|
|
396
404
|
opts[:queues] ||= []
|
397
405
|
opts[:strict] = true if opts[:strict].nil?
|
398
406
|
raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
|
399
|
-
[weight.to_i, 1].max.times { opts[:queues] << queue }
|
407
|
+
[weight.to_i, 1].max.times { opts[:queues] << queue.to_s }
|
400
408
|
opts[:strict] = false if weight.to_i > 0
|
401
409
|
end
|
402
410
|
|
data/lib/sidekiq/client.rb
CHANGED
@@ -95,7 +95,7 @@ module Sidekiq
|
|
95
95
|
return [] if args.empty? # no jobs to push
|
96
96
|
|
97
97
|
at = items.delete("at")
|
98
|
-
raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all?(Numeric))
|
98
|
+
raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all? { |entry| entry.is_a?(Numeric) })
|
99
99
|
raise ArgumentError, "Job 'at' Array must have same size as 'args' Array" if at.is_a?(Array) && at.size != args.size
|
100
100
|
|
101
101
|
normed = normalize_item(items)
|
@@ -186,7 +186,7 @@ module Sidekiq
|
|
186
186
|
|
187
187
|
def raw_push(payloads)
|
188
188
|
@redis_pool.with do |conn|
|
189
|
-
conn.
|
189
|
+
conn.pipelined do
|
190
190
|
atomic_push(conn, payloads)
|
191
191
|
end
|
192
192
|
end
|
data/lib/sidekiq/fetch.rb
CHANGED
data/lib/sidekiq/job.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require "sidekiq/worker"
|
2
2
|
|
3
3
|
module Sidekiq
|
4
|
-
# Sidekiq::Job is a new alias for Sidekiq::Worker
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
|
5
|
+
# Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
|
6
|
+
#
|
7
|
+
# The term "worker" is too generic and overly confusing, used in several
|
8
|
+
# different contexts meaning different things. Many people call a Sidekiq
|
9
|
+
# process a "worker". Some people call the thread that executes jobs a
|
10
|
+
# "worker". This change brings Sidekiq closer to ActiveJob where your job
|
11
|
+
# classes extend ApplicationJob.
|
7
12
|
Job = Worker
|
8
13
|
end
|
data/lib/sidekiq/launcher.rb
CHANGED
@@ -69,10 +69,12 @@ module Sidekiq
|
|
69
69
|
|
70
70
|
private unless $TESTING
|
71
71
|
|
72
|
+
BEAT_PAUSE = 5
|
73
|
+
|
72
74
|
def start_heartbeat
|
73
75
|
loop do
|
74
76
|
heartbeat
|
75
|
-
sleep
|
77
|
+
sleep BEAT_PAUSE
|
76
78
|
end
|
77
79
|
Sidekiq.logger.info("Heartbeat stopping...")
|
78
80
|
end
|
@@ -211,6 +213,8 @@ module Sidekiq
|
|
211
213
|
Your Redis network connection is performing extremely poorly.
|
212
214
|
Last RTT readings were #{RTT_READINGS.buffer.inspect}, ideally these should be < 1000.
|
213
215
|
Ensure Redis is running in the same AZ or datacenter as Sidekiq.
|
216
|
+
If these values are close to 100,000, that means your Sidekiq process may be
|
217
|
+
CPU overloaded; see https://github.com/mperham/sidekiq/discussions/5039
|
214
218
|
EOM
|
215
219
|
RTT_READINGS.reset
|
216
220
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "active_support/current_attributes"
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
##
|
5
|
+
# Automatically save and load any current attributes in the execution context
|
6
|
+
# so context attributes "flow" from Rails actions into any associated jobs.
|
7
|
+
# This can be useful for multi-tenancy, i18n locale, timezone, any implicit
|
8
|
+
# per-request attribute. See +ActiveSupport::CurrentAttributes+.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # in your initializer
|
13
|
+
# require "sidekiq/middleware/current_attributes"
|
14
|
+
# Sidekiq::CurrentAttributes.persist(Myapp::Current)
|
15
|
+
#
|
16
|
+
module CurrentAttributes
|
17
|
+
class Save
|
18
|
+
def initialize(with:)
|
19
|
+
@klass = with
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(_, job, _, _)
|
23
|
+
job["ctx"] = @klass.attributes
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Load
|
29
|
+
def initialize(with:)
|
30
|
+
@klass = with
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(_, job, _, &block)
|
34
|
+
@klass.set(job["ctx"], &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.persist(klass)
|
39
|
+
Sidekiq.configure_client do |config|
|
40
|
+
config.client_middleware.add Save, with: klass
|
41
|
+
end
|
42
|
+
Sidekiq.configure_server do |config|
|
43
|
+
config.client_middleware.add Save, with: klass
|
44
|
+
config.server_middleware.add Load, with: klass
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -37,6 +37,17 @@ module Sidekiq
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
initializer "sidekiq.rails_logger" do
|
41
|
+
Sidekiq.configure_server do |_|
|
42
|
+
# This is the integration code necessary so that if code uses `Rails.logger.info "Hello"`,
|
43
|
+
# it will appear in the Sidekiq console with all of the job context. See #5021 and
|
44
|
+
# https://github.com/rails/rails/blob/b5f2b550f69a99336482739000c58e4e04e033aa/railties/lib/rails/commands/server/server_command.rb#L82-L84
|
45
|
+
unless ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
46
|
+
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(::Sidekiq.logger))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
40
51
|
# This hook happens after all initializers are run, just before returning
|
41
52
|
# from config/environment.rb back to sidekiq/cli.rb.
|
42
53
|
#
|
@@ -94,12 +94,10 @@ module Sidekiq
|
|
94
94
|
def log_info(options)
|
95
95
|
redacted = "REDACTED"
|
96
96
|
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
|
101
|
-
keys = options.keys
|
102
|
-
keys.delete(:ssl_params)
|
97
|
+
# Deep clone so we can muck with these options all we want and exclude
|
98
|
+
# params from dump-and-load that may contain objects that Marshal is
|
99
|
+
# unable to safely dump.
|
100
|
+
keys = options.keys - [:logger, :ssl_params]
|
103
101
|
scrubbed_options = Marshal.load(Marshal.dump(options.slice(*keys)))
|
104
102
|
if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password
|
105
103
|
uri.password = redacted
|
data/lib/sidekiq/scheduled.rb
CHANGED
@@ -9,29 +9,48 @@ module Sidekiq
|
|
9
9
|
SETS = %w[retry schedule]
|
10
10
|
|
11
11
|
class Enq
|
12
|
+
LUA_ZPOPBYSCORE = <<~LUA
|
13
|
+
local key, now = KEYS[1], ARGV[1]
|
14
|
+
local jobs = redis.call("zrangebyscore", key, "-inf", now, "limit", 0, 1)
|
15
|
+
if jobs[1] then
|
16
|
+
redis.call("zrem", key, jobs[1])
|
17
|
+
return jobs[1]
|
18
|
+
end
|
19
|
+
LUA
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@lua_zpopbyscore_sha = nil
|
23
|
+
end
|
24
|
+
|
12
25
|
def enqueue_jobs(now = Time.now.to_f.to_s, sorted_sets = SETS)
|
13
26
|
# A job's "score" in Redis is the time at which it should be processed.
|
14
27
|
# Just check Redis for the set of jobs with a timestamp before now.
|
15
28
|
Sidekiq.redis do |conn|
|
16
29
|
sorted_sets.each do |sorted_set|
|
17
|
-
# Get next
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# the queue, it's because another process already popped it so we can move on to the
|
25
|
-
# next one.
|
26
|
-
if conn.zrem(sorted_set, job)
|
27
|
-
Sidekiq::Client.push(Sidekiq.load_json(job))
|
28
|
-
Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
|
29
|
-
end
|
30
|
-
end
|
30
|
+
# Get next item in the queue with score (time to execute) <= now.
|
31
|
+
# We need to go through the list one at a time to reduce the risk of something
|
32
|
+
# going wrong between the time jobs are popped from the scheduled queue and when
|
33
|
+
# they are pushed onto a work queue and losing the jobs.
|
34
|
+
while (job = zpopbyscore(conn, keys: [sorted_set], argv: [now]))
|
35
|
+
Sidekiq::Client.push(Sidekiq.load_json(job))
|
36
|
+
Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def zpopbyscore(conn, keys: nil, argv: nil)
|
45
|
+
@lua_zpopbyscore_sha = conn.script(:load, LUA_ZPOPBYSCORE) if @lua_zpopbyscore_sha.nil?
|
46
|
+
|
47
|
+
conn.evalsha(@lua_zpopbyscore_sha, keys: keys, argv: argv)
|
48
|
+
rescue Redis::CommandError => e
|
49
|
+
raise unless e.message.start_with?("NOSCRIPT")
|
50
|
+
|
51
|
+
@lua_zpopbyscore_sha = nil
|
52
|
+
retry
|
53
|
+
end
|
35
54
|
end
|
36
55
|
|
37
56
|
##
|
data/lib/sidekiq/version.rb
CHANGED
@@ -91,8 +91,8 @@ module Sidekiq
|
|
91
91
|
|
92
92
|
@count = (params["count"] || 25).to_i
|
93
93
|
@queue = Sidekiq::Queue.new(@name)
|
94
|
-
(@current_page, @total_size, @
|
95
|
-
@
|
94
|
+
(@current_page, @total_size, @jobs) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc")
|
95
|
+
@jobs = @jobs.map { |msg| Sidekiq::JobRecord.new(msg, @name) }
|
96
96
|
|
97
97
|
erb(:queue)
|
98
98
|
end
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -70,17 +70,6 @@ module Sidekiq
|
|
70
70
|
@head_html.join if defined?(@head_html)
|
71
71
|
end
|
72
72
|
|
73
|
-
def poll_path
|
74
|
-
if current_path != "" && params["poll"]
|
75
|
-
path = root_path + current_path
|
76
|
-
query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
|
77
|
-
path += "?#{query_string}" unless query_string.empty?
|
78
|
-
path
|
79
|
-
else
|
80
|
-
""
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
73
|
def text_direction
|
85
74
|
get_locale["TextDirection"] || "ltr"
|
86
75
|
end
|
@@ -203,7 +192,7 @@ module Sidekiq
|
|
203
192
|
[score.to_f, jid]
|
204
193
|
end
|
205
194
|
|
206
|
-
SAFE_QPARAMS = %w[page
|
195
|
+
SAFE_QPARAMS = %w[page direction]
|
207
196
|
|
208
197
|
# Merge options with current params, filter safe params, and stringify to query string
|
209
198
|
def qparams(options)
|
data/lib/sidekiq/worker.rb
CHANGED
@@ -9,6 +9,7 @@ module Sidekiq
|
|
9
9
|
#
|
10
10
|
# class HardWorker
|
11
11
|
# include Sidekiq::Worker
|
12
|
+
# sidekiq_options queue: 'critical', retry: 5
|
12
13
|
#
|
13
14
|
# def perform(*args)
|
14
15
|
# # do some work
|
@@ -20,6 +21,26 @@ module Sidekiq
|
|
20
21
|
# HardWorker.perform_async(1, 2, 3)
|
21
22
|
#
|
22
23
|
# Note that perform_async is a class method, perform is an instance method.
|
24
|
+
#
|
25
|
+
# Sidekiq::Worker also includes several APIs to provide compatibility with
|
26
|
+
# ActiveJob.
|
27
|
+
#
|
28
|
+
# class SomeWorker
|
29
|
+
# include Sidekiq::Worker
|
30
|
+
# queue_as :critical
|
31
|
+
#
|
32
|
+
# def perform(...)
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# SomeWorker.set(wait_until: 1.hour).perform_async(123)
|
37
|
+
#
|
38
|
+
# Note that arguments passed to the job must still obey Sidekiq's
|
39
|
+
# best practice for simple, JSON-native data types. Sidekiq will not
|
40
|
+
# implement ActiveJob's more complex argument serialization. For
|
41
|
+
# this reason, we don't implement `perform_later` as our call semantics
|
42
|
+
# are very different.
|
43
|
+
#
|
23
44
|
module Worker
|
24
45
|
##
|
25
46
|
# The Options module is extracted so we can include it in ActiveJob::Base
|
@@ -153,10 +174,16 @@ module Sidekiq
|
|
153
174
|
def initialize(klass, opts)
|
154
175
|
@klass = klass
|
155
176
|
@opts = opts
|
177
|
+
|
178
|
+
# ActiveJob compatibility
|
179
|
+
interval = @opts.delete(:wait_until) || @opts.delete(:wait)
|
180
|
+
at(interval) if interval
|
156
181
|
end
|
157
182
|
|
158
183
|
def set(options)
|
184
|
+
interval = options.delete(:wait_until) || options.delete(:wait)
|
159
185
|
@opts.merge!(options)
|
186
|
+
at(interval) if interval
|
160
187
|
self
|
161
188
|
end
|
162
189
|
|
@@ -164,19 +191,29 @@ module Sidekiq
|
|
164
191
|
@klass.client_push(@opts.merge("args" => args, "class" => @klass))
|
165
192
|
end
|
166
193
|
|
194
|
+
def perform_bulk(args, batch_size: 1_000)
|
195
|
+
args.each_slice(batch_size).flat_map do |slice|
|
196
|
+
Sidekiq::Client.push_bulk(@opts.merge("class" => @klass, "args" => slice))
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
167
200
|
# +interval+ must be a timestamp, numeric or something that acts
|
168
201
|
# numeric (like an activesupport time interval).
|
169
202
|
def perform_in(interval, *args)
|
203
|
+
at(interval).perform_async(*args)
|
204
|
+
end
|
205
|
+
alias_method :perform_at, :perform_in
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def at(interval)
|
170
210
|
int = interval.to_f
|
171
211
|
now = Time.now.to_f
|
172
212
|
ts = (int < 1_000_000_000 ? now + int : int)
|
173
|
-
|
174
|
-
payload = @opts.merge("class" => @klass, "args" => args)
|
175
213
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
176
|
-
|
177
|
-
|
214
|
+
@opts["at"] = ts if ts > now
|
215
|
+
self
|
178
216
|
end
|
179
|
-
alias_method :perform_at, :perform_in
|
180
217
|
end
|
181
218
|
|
182
219
|
module ClassMethods
|
@@ -192,6 +229,10 @@ module Sidekiq
|
|
192
229
|
raise ArgumentError, "Do not call .delay_until on a Sidekiq::Worker class, call .perform_at"
|
193
230
|
end
|
194
231
|
|
232
|
+
def queue_as(q)
|
233
|
+
sidekiq_options("queue" => q.to_s)
|
234
|
+
end
|
235
|
+
|
195
236
|
def set(options)
|
196
237
|
Setter.new(self, options)
|
197
238
|
end
|
@@ -200,6 +241,32 @@ module Sidekiq
|
|
200
241
|
client_push("class" => self, "args" => args)
|
201
242
|
end
|
202
243
|
|
244
|
+
##
|
245
|
+
# Push a large number of jobs to Redis, while limiting the batch of
|
246
|
+
# each job payload to 1,000. This method helps cut down on the number
|
247
|
+
# of round trips to Redis, which can increase the performance of enqueueing
|
248
|
+
# large numbers of jobs.
|
249
|
+
#
|
250
|
+
# +items+ must be an Array of Arrays.
|
251
|
+
#
|
252
|
+
# For finer-grained control, use `Sidekiq::Client.push_bulk` directly.
|
253
|
+
#
|
254
|
+
# Example (3 Redis round trips):
|
255
|
+
#
|
256
|
+
# SomeWorker.perform_async(1)
|
257
|
+
# SomeWorker.perform_async(2)
|
258
|
+
# SomeWorker.perform_async(3)
|
259
|
+
#
|
260
|
+
# Would instead become (1 Redis round trip):
|
261
|
+
#
|
262
|
+
# SomeWorker.perform_bulk([[1], [2], [3]])
|
263
|
+
#
|
264
|
+
def perform_bulk(items, batch_size: 1_000)
|
265
|
+
items.each_slice(batch_size).flat_map do |slice|
|
266
|
+
Sidekiq::Client.push_bulk("class" => self, "args" => slice)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
203
270
|
# +interval+ must be a timestamp, numeric or something that acts
|
204
271
|
# numeric (like an activesupport time interval).
|
205
272
|
def perform_in(interval, *args)
|
data/lib/sidekiq.rb
CHANGED
@@ -6,6 +6,7 @@ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.5.0." i
|
|
6
6
|
require "sidekiq/logger"
|
7
7
|
require "sidekiq/client"
|
8
8
|
require "sidekiq/worker"
|
9
|
+
require "sidekiq/job"
|
9
10
|
require "sidekiq/redis_connection"
|
10
11
|
require "sidekiq/delay"
|
11
12
|
|
@@ -100,7 +101,8 @@ module Sidekiq
|
|
100
101
|
# 2550 Failover can cause the server to become a replica, need
|
101
102
|
# to disconnect and reopen the socket to get back to the primary.
|
102
103
|
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
103
|
-
|
104
|
+
# 4985 Use the same logic when a blocking command is force-unblocked
|
105
|
+
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
104
106
|
conn.disconnect!
|
105
107
|
retryable = false
|
106
108
|
retry
|
data/sidekiq.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
|
|
18
18
|
"homepage_uri" => "https://sidekiq.org",
|
19
19
|
"bug_tracker_uri" => "https://github.com/mperham/sidekiq/issues",
|
20
20
|
"documentation_uri" => "https://github.com/mperham/sidekiq/wiki",
|
21
|
-
"changelog_uri" => "https://github.com/mperham/sidekiq/blob/
|
21
|
+
"changelog_uri" => "https://github.com/mperham/sidekiq/blob/main/Changes.md",
|
22
22
|
"source_code_uri" => "https://github.com/mperham/sidekiq"
|
23
23
|
}
|
24
24
|
|