sidekiq 6.5.5 → 6.5.12
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/Changes.md +37 -0
- data/bin/sidekiqload +2 -2
- data/lib/sidekiq/api.rb +35 -15
- data/lib/sidekiq/cli.rb +12 -0
- data/lib/sidekiq/client.rb +2 -2
- data/lib/sidekiq/fetch.rb +2 -2
- data/lib/sidekiq/launcher.rb +2 -2
- data/lib/sidekiq/metrics/query.rb +1 -1
- data/lib/sidekiq/middleware/current_attributes.rb +8 -8
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +9 -1
- data/lib/sidekiq/rails.rb +10 -11
- data/lib/sidekiq/redis_connection.rb +0 -2
- data/lib/sidekiq/scheduled.rb +42 -8
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +3 -0
- data/lib/sidekiq/web/helpers.rb +7 -17
- data/lib/sidekiq/worker.rb +6 -3
- data/sidekiq.gemspec +2 -2
- data/web/assets/javascripts/application.js +1 -0
- data/web/locales/ja.yml +7 -0
- data/web/locales/zh-cn.yml +36 -11
- data/web/locales/zh-tw.yml +32 -7
- data/web/views/busy.erb +6 -1
- metadata +17 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55c6f9a8c0f2810bcbe7744c95204893d73f534666f6091c74dcb5199e7a4a28
|
|
4
|
+
data.tar.gz: c42690ef0d1876c94eb51fb68319275d11f10169826180db921b34d6334a1a54
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 461b559e18cbdf8fe6ba20ab9fa38d08fd3b7b8d14dce7a7f9369d678e92bd25c07734bc14b0167f83589c0f03501897195b3fdf9cfd5de5a60f039bf7436f98
|
|
7
|
+
data.tar.gz: ce0490b438a22a71c37e5a65193a7728e3297b437730d30a3653807ff1e89476db1f8c62d8de50c0c8cebbbce2ba6fb65f110855e071c62746fe8697a0f636e1
|
data/Changes.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
+
6.5.11
|
|
6
|
+
----------
|
|
7
|
+
|
|
8
|
+
- Fix for Rails 7.1 [#6067]
|
|
9
|
+
|
|
10
|
+
6.5.10
|
|
11
|
+
----------
|
|
12
|
+
|
|
13
|
+
- Web UI DoS vector [#6045] CVE-2023-26141
|
|
14
|
+
- Fix broadcast logger with Rails 7.1 [#6054]
|
|
15
|
+
|
|
16
|
+
6.5.9
|
|
17
|
+
----------
|
|
18
|
+
|
|
19
|
+
- Ensure Sidekiq.options[:environment] == RAILS_ENV [#5932]
|
|
20
|
+
|
|
21
|
+
6.5.8
|
|
22
|
+
----------
|
|
23
|
+
|
|
24
|
+
- Fail if using a bad version of scout_apm [#5616]
|
|
25
|
+
- Add pagination to Busy page [#5556]
|
|
26
|
+
- Speed up WorkSet#each [#5559]
|
|
27
|
+
- Adjust CurrentAttributes to work with the String class name so we aren't referencing
|
|
28
|
+
the Class within a Rails initializer [#5536]
|
|
29
|
+
|
|
30
|
+
6.5.7
|
|
31
|
+
----------
|
|
32
|
+
|
|
33
|
+
- Updates for JA and ZH locales
|
|
34
|
+
- Further optimizations for scheduled polling [#5513]
|
|
35
|
+
|
|
36
|
+
6.5.6
|
|
37
|
+
----------
|
|
38
|
+
|
|
39
|
+
- Fix deprecation warnings with redis-rb 4.8.0 [#5484]
|
|
40
|
+
- Lock redis-rb to < 5.0 as we are moving to redis-client in Sidekiq 7.0
|
|
41
|
+
|
|
5
42
|
6.5.5
|
|
6
43
|
----------
|
|
7
44
|
|
data/bin/sidekiqload
CHANGED
|
@@ -89,7 +89,7 @@ def Process.rss
|
|
|
89
89
|
`ps -o rss= -p #{Process.pid}`.chomp.to_i
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
iter =
|
|
92
|
+
iter = 10
|
|
93
93
|
count = 10_000
|
|
94
94
|
|
|
95
95
|
iter.times do
|
|
@@ -139,7 +139,7 @@ begin
|
|
|
139
139
|
events.clear
|
|
140
140
|
|
|
141
141
|
with_latency(Integer(ENV.fetch("LATENCY", "1"))) do
|
|
142
|
-
launcher = Sidekiq::Launcher.new(Sidekiq
|
|
142
|
+
launcher = Sidekiq::Launcher.new(Sidekiq)
|
|
143
143
|
launcher.run
|
|
144
144
|
|
|
145
145
|
while readable_io = IO.select([self_read])
|
data/lib/sidekiq/api.rb
CHANGED
|
@@ -11,6 +11,17 @@ if ENV["SIDEKIQ_METRICS_BETA"]
|
|
|
11
11
|
require "sidekiq/metrics/query"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
#
|
|
15
|
+
# Sidekiq's Data API provides a Ruby object model on top
|
|
16
|
+
# of Sidekiq's runtime data in Redis. This API should never
|
|
17
|
+
# be used within application code for business logic.
|
|
18
|
+
#
|
|
19
|
+
# The Sidekiq server process never uses this API: all data
|
|
20
|
+
# manipulation is done directly for performance reasons to
|
|
21
|
+
# ensure we are using Redis as efficiently as possible at
|
|
22
|
+
# every callsite.
|
|
23
|
+
#
|
|
24
|
+
|
|
14
25
|
module Sidekiq
|
|
15
26
|
# Retrieve runtime statistics from Redis regarding
|
|
16
27
|
# this Sidekiq cluster.
|
|
@@ -316,7 +327,7 @@ module Sidekiq
|
|
|
316
327
|
Sidekiq.redis do |conn|
|
|
317
328
|
conn.multi do |transaction|
|
|
318
329
|
transaction.unlink(@rname)
|
|
319
|
-
transaction.srem("queues", name)
|
|
330
|
+
transaction.srem("queues", [name])
|
|
320
331
|
end
|
|
321
332
|
end
|
|
322
333
|
true
|
|
@@ -486,7 +497,7 @@ module Sidekiq
|
|
|
486
497
|
# #1761 in dev mode, it's possible to have jobs enqueued which haven't been loaded into
|
|
487
498
|
# memory yet so the YAML can't be loaded.
|
|
488
499
|
# TODO is this still necessary? Zeitwerk reloader should handle?
|
|
489
|
-
Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.
|
|
500
|
+
Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.options[:environment] == "development"
|
|
490
501
|
default
|
|
491
502
|
end
|
|
492
503
|
|
|
@@ -893,10 +904,12 @@ module Sidekiq
|
|
|
893
904
|
# :nodoc:
|
|
894
905
|
# @api private
|
|
895
906
|
def cleanup
|
|
907
|
+
# dont run cleanup more than once per minute
|
|
896
908
|
return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
|
|
909
|
+
|
|
897
910
|
count = 0
|
|
898
911
|
Sidekiq.redis do |conn|
|
|
899
|
-
procs = conn.sscan_each("processes").to_a
|
|
912
|
+
procs = conn.sscan_each("processes").to_a
|
|
900
913
|
heartbeats = conn.pipelined { |pipeline|
|
|
901
914
|
procs.each do |key|
|
|
902
915
|
pipeline.hget(key, "info")
|
|
@@ -1090,24 +1103,31 @@ module Sidekiq
|
|
|
1090
1103
|
|
|
1091
1104
|
def each(&block)
|
|
1092
1105
|
results = []
|
|
1106
|
+
procs = nil
|
|
1107
|
+
all_works = nil
|
|
1108
|
+
|
|
1093
1109
|
Sidekiq.redis do |conn|
|
|
1094
|
-
procs = conn.sscan_each("processes").to_a
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1110
|
+
procs = conn.sscan_each("processes").to_a.sort
|
|
1111
|
+
|
|
1112
|
+
all_works = conn.pipelined do |pipeline|
|
|
1113
|
+
procs.each do |key|
|
|
1098
1114
|
pipeline.hgetall("#{key}:work")
|
|
1099
|
-
}
|
|
1100
|
-
next unless valid
|
|
1101
|
-
workers.each_pair do |tid, json|
|
|
1102
|
-
hsh = Sidekiq.load_json(json)
|
|
1103
|
-
p = hsh["payload"]
|
|
1104
|
-
# avoid breaking API, this is a side effect of the JSON optimization in #4316
|
|
1105
|
-
hsh["payload"] = Sidekiq.load_json(p) if p.is_a?(String)
|
|
1106
|
-
results << [key, tid, hsh]
|
|
1107
1115
|
end
|
|
1108
1116
|
end
|
|
1109
1117
|
end
|
|
1110
1118
|
|
|
1119
|
+
procs.zip(all_works).each do |key, workers|
|
|
1120
|
+
workers.each_pair do |tid, json|
|
|
1121
|
+
next if json.empty?
|
|
1122
|
+
|
|
1123
|
+
hsh = Sidekiq.load_json(json)
|
|
1124
|
+
p = hsh["payload"]
|
|
1125
|
+
# avoid breaking API, this is a side effect of the JSON optimization in #4316
|
|
1126
|
+
hsh["payload"] = Sidekiq.load_json(p) if p.is_a?(String)
|
|
1127
|
+
results << [key, tid, hsh]
|
|
1128
|
+
end
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1111
1131
|
results.sort_by { |(_, _, hsh)| hsh["run_at"] }.each(&block)
|
|
1112
1132
|
end
|
|
1113
1133
|
|
data/lib/sidekiq/cli.rb
CHANGED
|
@@ -12,6 +12,17 @@ require "sidekiq"
|
|
|
12
12
|
require "sidekiq/component"
|
|
13
13
|
require "sidekiq/launcher"
|
|
14
14
|
|
|
15
|
+
# module ScoutApm
|
|
16
|
+
# VERSION = "5.3.1"
|
|
17
|
+
# end
|
|
18
|
+
fail <<~EOM if defined?(ScoutApm::VERSION) && ScoutApm::VERSION < "5.2.0"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
scout_apm v#{ScoutApm::VERSION} is unsafe with Sidekiq 6.5. Please run `bundle up scout_apm` to upgrade to 5.2.0 or greater.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
EOM
|
|
25
|
+
|
|
15
26
|
module Sidekiq # :nodoc:
|
|
16
27
|
class CLI
|
|
17
28
|
include Sidekiq::Component
|
|
@@ -214,6 +225,7 @@ module Sidekiq # :nodoc:
|
|
|
214
225
|
# Both Sinatra 2.0+ and Sidekiq support this term.
|
|
215
226
|
# RAILS_ENV and RACK_ENV are there for legacy support.
|
|
216
227
|
@environment = cli_env || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
228
|
+
config[:environment] = @environment
|
|
217
229
|
end
|
|
218
230
|
|
|
219
231
|
def symbolize_keys_deep!(hash)
|
data/lib/sidekiq/client.rb
CHANGED
|
@@ -176,7 +176,7 @@ module Sidekiq
|
|
|
176
176
|
def enqueue_to_in(queue, interval, klass, *args)
|
|
177
177
|
int = interval.to_f
|
|
178
178
|
now = Time.now.to_f
|
|
179
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
|
179
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
|
180
180
|
|
|
181
181
|
item = {"class" => klass, "args" => args, "at" => ts, "queue" => queue}
|
|
182
182
|
item.delete("at") if ts <= now
|
|
@@ -231,7 +231,7 @@ module Sidekiq
|
|
|
231
231
|
entry["enqueued_at"] = now
|
|
232
232
|
Sidekiq.dump_json(entry)
|
|
233
233
|
}
|
|
234
|
-
conn.sadd("queues", queue)
|
|
234
|
+
conn.sadd("queues", [queue])
|
|
235
235
|
conn.lpush("queue:#{queue}", to_push)
|
|
236
236
|
end
|
|
237
237
|
end
|
data/lib/sidekiq/fetch.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Sidekiq # :nodoc:
|
|
|
33
33
|
@queues = @config[:queues].map { |q| "queue:#{q}" }
|
|
34
34
|
if @strictly_ordered_queues
|
|
35
35
|
@queues.uniq!
|
|
36
|
-
@queues << TIMEOUT
|
|
36
|
+
@queues << {timeout: TIMEOUT}
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -83,7 +83,7 @@ module Sidekiq # :nodoc:
|
|
|
83
83
|
else
|
|
84
84
|
permute = @queues.shuffle
|
|
85
85
|
permute.uniq!
|
|
86
|
-
permute << TIMEOUT
|
|
86
|
+
permute << {timeout: TIMEOUT}
|
|
87
87
|
permute
|
|
88
88
|
end
|
|
89
89
|
end
|
data/lib/sidekiq/launcher.rb
CHANGED
|
@@ -86,7 +86,7 @@ module Sidekiq
|
|
|
86
86
|
# doesn't actually exit, it'll reappear in the Web UI.
|
|
87
87
|
redis do |conn|
|
|
88
88
|
conn.pipelined do |pipeline|
|
|
89
|
-
pipeline.srem("processes", identity)
|
|
89
|
+
pipeline.srem("processes", [identity])
|
|
90
90
|
pipeline.unlink("#{identity}:work")
|
|
91
91
|
end
|
|
92
92
|
end
|
|
@@ -165,7 +165,7 @@ module Sidekiq
|
|
|
165
165
|
|
|
166
166
|
_, exists, _, _, msg = redis { |conn|
|
|
167
167
|
conn.multi { |transaction|
|
|
168
|
-
transaction.sadd("processes", key)
|
|
168
|
+
transaction.sadd("processes", [key])
|
|
169
169
|
transaction.exists?(key)
|
|
170
170
|
transaction.hmset(key, "info", to_json,
|
|
171
171
|
"busy", curstate.size,
|
|
@@ -123,7 +123,7 @@ module Sidekiq
|
|
|
123
123
|
def series_avg(metric = "ms")
|
|
124
124
|
series[metric].each_with_object(Hash.new(0)) do |(bucket, value), result|
|
|
125
125
|
completed = series.dig("p", bucket) - series.dig("f", bucket)
|
|
126
|
-
result[bucket] = completed == 0 ? 0 : value.to_f / completed
|
|
126
|
+
result[bucket] = (completed == 0) ? 0 : value.to_f / completed
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
end
|
|
@@ -11,18 +11,18 @@ module Sidekiq
|
|
|
11
11
|
#
|
|
12
12
|
# # in your initializer
|
|
13
13
|
# require "sidekiq/middleware/current_attributes"
|
|
14
|
-
# Sidekiq::CurrentAttributes.persist(Myapp::Current)
|
|
14
|
+
# Sidekiq::CurrentAttributes.persist("Myapp::Current")
|
|
15
15
|
#
|
|
16
16
|
module CurrentAttributes
|
|
17
17
|
class Save
|
|
18
18
|
include Sidekiq::ClientMiddleware
|
|
19
19
|
|
|
20
20
|
def initialize(cattr)
|
|
21
|
-
@
|
|
21
|
+
@strklass = cattr
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def call(_, job, _, _)
|
|
25
|
-
attrs = @
|
|
25
|
+
attrs = @strklass.constantize.attributes
|
|
26
26
|
if attrs.any?
|
|
27
27
|
if job.has_key?("cattr")
|
|
28
28
|
job["cattr"].merge!(attrs)
|
|
@@ -38,12 +38,12 @@ module Sidekiq
|
|
|
38
38
|
include Sidekiq::ServerMiddleware
|
|
39
39
|
|
|
40
40
|
def initialize(cattr)
|
|
41
|
-
@
|
|
41
|
+
@strklass = cattr
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def call(_, job, _, &block)
|
|
45
45
|
if job.has_key?("cattr")
|
|
46
|
-
@
|
|
46
|
+
@strklass.constantize.set(job["cattr"], &block)
|
|
47
47
|
else
|
|
48
48
|
yield
|
|
49
49
|
end
|
|
@@ -52,11 +52,11 @@ module Sidekiq
|
|
|
52
52
|
|
|
53
53
|
def self.persist(klass)
|
|
54
54
|
Sidekiq.configure_client do |config|
|
|
55
|
-
config.client_middleware.add Save, klass
|
|
55
|
+
config.client_middleware.add Save, klass.to_s
|
|
56
56
|
end
|
|
57
57
|
Sidekiq.configure_server do |config|
|
|
58
|
-
config.client_middleware.add Save, klass
|
|
59
|
-
config.server_middleware.add Load, klass
|
|
58
|
+
config.client_middleware.add Save, klass.to_s
|
|
59
|
+
config.server_middleware.add Load, klass.to_s
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
data/lib/sidekiq/monitor.rb
CHANGED
|
@@ -101,7 +101,7 @@ class Sidekiq::Monitor
|
|
|
101
101
|
tags = [
|
|
102
102
|
process["tag"],
|
|
103
103
|
process["labels"],
|
|
104
|
-
(process["quiet"] == "true" ? "quiet" : nil)
|
|
104
|
+
((process["quiet"] == "true") ? "quiet" : nil)
|
|
105
105
|
].flatten.compact
|
|
106
106
|
tags.any? ? "[#{tags.join("] [")}]" : nil
|
|
107
107
|
end
|
data/lib/sidekiq/paginator.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Sidekiq
|
|
4
4
|
module Paginator
|
|
5
5
|
def page(key, pageidx = 1, page_size = 25, opts = nil)
|
|
6
|
-
current_page = pageidx.to_i < 1 ? 1 : pageidx.to_i
|
|
6
|
+
current_page = (pageidx.to_i < 1) ? 1 : pageidx.to_i
|
|
7
7
|
pageidx = current_page - 1
|
|
8
8
|
total_size = 0
|
|
9
9
|
items = []
|
|
@@ -43,5 +43,13 @@ module Sidekiq
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
def page_items(items, pageidx = 1, page_size = 25)
|
|
48
|
+
current_page = (pageidx.to_i < 1) ? 1 : pageidx.to_i
|
|
49
|
+
pageidx = current_page - 1
|
|
50
|
+
starting = pageidx * page_size
|
|
51
|
+
items = items.to_a
|
|
52
|
+
[current_page, items.size, items[starting, page_size]]
|
|
53
|
+
end
|
|
46
54
|
end
|
|
47
55
|
end
|
data/lib/sidekiq/rails.rb
CHANGED
|
@@ -37,17 +37,6 @@ module Sidekiq
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
initializer "sidekiq.rails_logger" do
|
|
41
|
-
Sidekiq.configure_server do |config|
|
|
42
|
-
# This is the integration code necessary so that if a job 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 ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
|
46
|
-
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
40
|
config.before_configuration do
|
|
52
41
|
dep = ActiveSupport::Deprecation.new("7.0", "Sidekiq")
|
|
53
42
|
dep.deprecate_methods(Sidekiq.singleton_class,
|
|
@@ -62,6 +51,16 @@ module Sidekiq
|
|
|
62
51
|
config.after_initialize do
|
|
63
52
|
Sidekiq.configure_server do |config|
|
|
64
53
|
config[:reloader] = Sidekiq::Rails::Reloader.new
|
|
54
|
+
|
|
55
|
+
# This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
|
|
56
|
+
# it will appear in the Sidekiq console with all of the job context.
|
|
57
|
+
unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
|
58
|
+
if ::Rails::VERSION::STRING < "7.1"
|
|
59
|
+
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
|
60
|
+
else
|
|
61
|
+
::Rails.logger.broadcast_to(config.logger)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
65
64
|
end
|
|
66
65
|
end
|
|
67
66
|
end
|
|
@@ -46,8 +46,6 @@ module Sidekiq
|
|
|
46
46
|
opts.delete(:network_timeout)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
opts[:driver] ||= Redis::Connection.drivers.last || "ruby"
|
|
50
|
-
|
|
51
49
|
# Issue #3303, redis-rb will silently retry an operation.
|
|
52
50
|
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
|
|
53
51
|
# is performed twice but I believe this is much, much rarer
|
data/lib/sidekiq/scheduled.rb
CHANGED
|
@@ -147,13 +147,16 @@ module Sidekiq
|
|
|
147
147
|
# As we run more processes, the scheduling interval average will approach an even spread
|
|
148
148
|
# between 0 and poll interval so we don't need this artifical boost.
|
|
149
149
|
#
|
|
150
|
-
|
|
150
|
+
count = process_count
|
|
151
|
+
interval = poll_interval_average(count)
|
|
152
|
+
|
|
153
|
+
if count < 10
|
|
151
154
|
# For small clusters, calculate a random interval that is ±50% the desired average.
|
|
152
|
-
|
|
155
|
+
interval * rand + interval.to_f / 2
|
|
153
156
|
else
|
|
154
157
|
# With 10+ processes, we should have enough randomness to get decent polling
|
|
155
158
|
# across the entire timespan
|
|
156
|
-
|
|
159
|
+
interval * rand
|
|
157
160
|
end
|
|
158
161
|
end
|
|
159
162
|
|
|
@@ -170,14 +173,14 @@ module Sidekiq
|
|
|
170
173
|
# the same time: the thundering herd problem.
|
|
171
174
|
#
|
|
172
175
|
# We only do this if poll_interval_average is unset (the default).
|
|
173
|
-
def poll_interval_average
|
|
174
|
-
@config[:poll_interval_average]
|
|
176
|
+
def poll_interval_average(count)
|
|
177
|
+
@config[:poll_interval_average] || scaled_poll_interval(count)
|
|
175
178
|
end
|
|
176
179
|
|
|
177
180
|
# Calculates an average poll interval based on the number of known Sidekiq processes.
|
|
178
181
|
# This minimizes a single point of failure by dispersing check-ins but without taxing
|
|
179
182
|
# Redis if you run many Sidekiq processes.
|
|
180
|
-
def scaled_poll_interval
|
|
183
|
+
def scaled_poll_interval(process_count)
|
|
181
184
|
process_count * @config[:average_scheduled_poll_interval]
|
|
182
185
|
end
|
|
183
186
|
|
|
@@ -187,9 +190,35 @@ module Sidekiq
|
|
|
187
190
|
pcount
|
|
188
191
|
end
|
|
189
192
|
|
|
193
|
+
# A copy of Sidekiq::ProcessSet#cleanup because server
|
|
194
|
+
# should never depend on sidekiq/api.
|
|
195
|
+
def cleanup
|
|
196
|
+
# dont run cleanup more than once per minute
|
|
197
|
+
return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
|
|
198
|
+
|
|
199
|
+
count = 0
|
|
200
|
+
Sidekiq.redis do |conn|
|
|
201
|
+
procs = conn.sscan_each("processes").to_a
|
|
202
|
+
heartbeats = conn.pipelined { |pipeline|
|
|
203
|
+
procs.each do |key|
|
|
204
|
+
pipeline.hget(key, "info")
|
|
205
|
+
end
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# the hash named key has an expiry of 60 seconds.
|
|
209
|
+
# if it's not found, that means the process has not reported
|
|
210
|
+
# in to Redis and probably died.
|
|
211
|
+
to_prune = procs.select.with_index { |proc, i|
|
|
212
|
+
heartbeats[i].nil?
|
|
213
|
+
}
|
|
214
|
+
count = conn.srem("processes", to_prune) unless to_prune.empty?
|
|
215
|
+
end
|
|
216
|
+
count
|
|
217
|
+
end
|
|
218
|
+
|
|
190
219
|
def initial_wait
|
|
191
|
-
# Have all processes sleep between 5-15 seconds.
|
|
192
|
-
#
|
|
220
|
+
# Have all processes sleep between 5-15 seconds. 10 seconds to give time for
|
|
221
|
+
# the heartbeat to register (if the poll interval is going to be calculated by the number
|
|
193
222
|
# of workers), and 5 random seconds to ensure they don't all hit Redis at the same time.
|
|
194
223
|
total = 0
|
|
195
224
|
total += INITIAL_WAIT unless @config[:poll_interval_average]
|
|
@@ -197,6 +226,11 @@ module Sidekiq
|
|
|
197
226
|
|
|
198
227
|
@sleeper.pop(total)
|
|
199
228
|
rescue Timeout::Error
|
|
229
|
+
ensure
|
|
230
|
+
# periodically clean out the `processes` set in Redis which can collect
|
|
231
|
+
# references to dead processes over time. The process count affects how
|
|
232
|
+
# often we scan for scheduled jobs.
|
|
233
|
+
cleanup
|
|
200
234
|
end
|
|
201
235
|
end
|
|
202
236
|
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/helpers.rb
CHANGED
|
@@ -137,7 +137,7 @@ module Sidekiq
|
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def sort_direction_label
|
|
140
|
-
params[:direction] == "asc" ? "↑" : "↓"
|
|
140
|
+
(params[:direction] == "asc") ? "↑" : "↓"
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
def workset
|
|
@@ -148,25 +148,15 @@ module Sidekiq
|
|
|
148
148
|
@processes ||= Sidekiq::ProcessSet.new
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
-
# Sorts processes by hostname following the natural sort order
|
|
152
|
-
# 'worker.1' < 'worker.2' < 'worker.10' < 'worker.20'
|
|
153
|
-
# '2.1.1.1' < '192.168.0.2' < '192.168.0.10'
|
|
151
|
+
# Sorts processes by hostname following the natural sort order
|
|
154
152
|
def sorted_processes
|
|
155
153
|
@sorted_processes ||= begin
|
|
156
154
|
return processes unless processes.all? { |p| p["hostname"] }
|
|
157
155
|
|
|
158
|
-
split_characters = /[._-]/
|
|
159
|
-
|
|
160
|
-
padding = processes.flat_map { |p| p["hostname"].split(split_characters) }.map(&:size).max
|
|
161
|
-
|
|
162
156
|
processes.to_a.sort_by do |process|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
padding_char = substring[0].match?(/\d/) ? "0" : "a"
|
|
167
|
-
|
|
168
|
-
substring.rjust(padding, padding_char)
|
|
169
|
-
end
|
|
157
|
+
# Kudos to `shurikk` on StackOverflow
|
|
158
|
+
# https://stackoverflow.com/a/15170063/575547
|
|
159
|
+
process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a }
|
|
170
160
|
end
|
|
171
161
|
end
|
|
172
162
|
end
|
|
@@ -198,7 +188,7 @@ module Sidekiq
|
|
|
198
188
|
end
|
|
199
189
|
|
|
200
190
|
def current_status
|
|
201
|
-
workset.size == 0 ? "idle" : "active"
|
|
191
|
+
(workset.size == 0) ? "idle" : "active"
|
|
202
192
|
end
|
|
203
193
|
|
|
204
194
|
def relative_time(time)
|
|
@@ -231,7 +221,7 @@ module Sidekiq
|
|
|
231
221
|
end
|
|
232
222
|
|
|
233
223
|
def truncate(text, truncate_after_chars = 2000)
|
|
234
|
-
truncate_after_chars && text.size > truncate_after_chars ? "#{text[0..truncate_after_chars]}..." : text
|
|
224
|
+
(truncate_after_chars && text.size > truncate_after_chars) ? "#{text[0..truncate_after_chars]}..." : text
|
|
235
225
|
end
|
|
236
226
|
|
|
237
227
|
def display_args(args, truncate_after_chars = 2000)
|
data/lib/sidekiq/worker.rb
CHANGED
|
@@ -257,7 +257,7 @@ module Sidekiq
|
|
|
257
257
|
def at(interval)
|
|
258
258
|
int = interval.to_f
|
|
259
259
|
now = Time.now.to_f
|
|
260
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
|
260
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
|
261
261
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
|
262
262
|
@opts["at"] = ts if ts > now
|
|
263
263
|
self
|
|
@@ -324,7 +324,7 @@ module Sidekiq
|
|
|
324
324
|
def perform_in(interval, *args)
|
|
325
325
|
int = interval.to_f
|
|
326
326
|
now = Time.now.to_f
|
|
327
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
|
327
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
|
328
328
|
|
|
329
329
|
item = {"class" => self, "args" => args}
|
|
330
330
|
|
|
@@ -340,7 +340,7 @@ module Sidekiq
|
|
|
340
340
|
# Legal options:
|
|
341
341
|
#
|
|
342
342
|
# queue - use a named queue for this Worker, default 'default'
|
|
343
|
-
# retry - enable
|
|
343
|
+
# retry - enable retries via JobRetry, *true* to use the default
|
|
344
344
|
# or *Integer* count
|
|
345
345
|
# backtrace - whether to save any error backtrace in the retry payload to display in web UI,
|
|
346
346
|
# can be true, false or an integer number of lines to save, default *false*
|
|
@@ -348,6 +348,9 @@ module Sidekiq
|
|
|
348
348
|
#
|
|
349
349
|
# In practice, any option is allowed. This is the main mechanism to configure the
|
|
350
350
|
# options for a specific job.
|
|
351
|
+
#
|
|
352
|
+
# These options will be saved into the serialized job when enqueued by
|
|
353
|
+
# the client.
|
|
351
354
|
def sidekiq_options(opts = {})
|
|
352
355
|
super
|
|
353
356
|
end
|
data/sidekiq.gemspec
CHANGED
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |gem|
|
|
|
22
22
|
"source_code_uri" => "https://github.com/mperham/sidekiq"
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
gem.add_dependency "redis", ">= 4.5.0"
|
|
26
|
-
gem.add_dependency "connection_pool", ">= 2.2.
|
|
25
|
+
gem.add_dependency "redis", ["<5", ">= 4.5.0"]
|
|
26
|
+
gem.add_dependency "connection_pool", ["<3", ">= 2.2.5"]
|
|
27
27
|
gem.add_dependency "rack", "~> 2.0"
|
|
28
28
|
end
|
data/web/locales/ja.yml
CHANGED
data/web/locales/zh-cn.yml
CHANGED
|
@@ -7,6 +7,7 @@ zh-cn: # <---- change this to your locale code
|
|
|
7
7
|
Realtime: 实时
|
|
8
8
|
History: 历史记录
|
|
9
9
|
Busy: 执行中
|
|
10
|
+
Utilization: 利用率
|
|
10
11
|
Processed: 已处理
|
|
11
12
|
Failed: 已失败
|
|
12
13
|
Scheduled: 已计划
|
|
@@ -17,15 +18,15 @@ zh-cn: # <---- change this to your locale code
|
|
|
17
18
|
StopPolling: 停止轮询
|
|
18
19
|
Queue: 队列
|
|
19
20
|
Class: 类别
|
|
20
|
-
Job:
|
|
21
|
+
Job: 任务
|
|
21
22
|
Arguments: 参数
|
|
22
23
|
Extras: 额外的
|
|
23
24
|
Started: 已开始
|
|
24
25
|
ShowAll: 显示全部
|
|
25
|
-
CurrentMessagesInQueue: 目前在<span class='title'>%{queue}</span
|
|
26
|
+
CurrentMessagesInQueue: 目前在<span class='title'>%{queue}</span>的任务
|
|
26
27
|
Delete: 删除
|
|
27
28
|
AddToQueue: 添加至队列
|
|
28
|
-
AreYouSureDeleteJob:
|
|
29
|
+
AreYouSureDeleteJob: 你确定要删除这个任务么?
|
|
29
30
|
AreYouSureDeleteQueue: 你确定要删除%{queue}这个队列?
|
|
30
31
|
Queues: 队列
|
|
31
32
|
Size: 容量
|
|
@@ -33,20 +34,22 @@ zh-cn: # <---- change this to your locale code
|
|
|
33
34
|
NextRetry: 下次重试
|
|
34
35
|
RetryCount: 重试次數
|
|
35
36
|
RetryNow: 现在重试
|
|
37
|
+
Kill: 终止
|
|
36
38
|
LastRetry: 最后一次重试
|
|
37
39
|
OriginallyFailed: 原本已失败
|
|
38
40
|
AreYouSure: 你确定?
|
|
39
|
-
DeleteAll:
|
|
40
|
-
RetryAll:
|
|
41
|
+
DeleteAll: 全部删除
|
|
42
|
+
RetryAll: 全部重试
|
|
43
|
+
KillAll: 全部终止
|
|
41
44
|
NoRetriesFound: 沒有发现可重试
|
|
42
45
|
Error: 错误
|
|
43
46
|
ErrorClass: 错误类别
|
|
44
47
|
ErrorMessage: 错误消息
|
|
45
|
-
ErrorBacktrace:
|
|
48
|
+
ErrorBacktrace: 错误细节
|
|
46
49
|
GoBack: ← 返回
|
|
47
|
-
NoScheduledFound:
|
|
50
|
+
NoScheduledFound: 沒有发现计划任务
|
|
48
51
|
When: 当
|
|
49
|
-
ScheduledJobs:
|
|
52
|
+
ScheduledJobs: 计划任务
|
|
50
53
|
idle: 闲置
|
|
51
54
|
active: 活动中
|
|
52
55
|
Version: 版本
|
|
@@ -59,10 +62,32 @@ zh-cn: # <---- change this to your locale code
|
|
|
59
62
|
ThreeMonths: 三个月
|
|
60
63
|
SixMonths: 六个月
|
|
61
64
|
Failures: 失败
|
|
62
|
-
DeadJobs:
|
|
63
|
-
NoDeadJobsFound:
|
|
65
|
+
DeadJobs: 已停滞任务
|
|
66
|
+
NoDeadJobsFound: 沒有发现任何已停滞的任务
|
|
64
67
|
Dead: 已停滞
|
|
68
|
+
Process: 进程
|
|
65
69
|
Processes: 处理中
|
|
70
|
+
Name: 名称
|
|
66
71
|
Thread: 线程
|
|
67
72
|
Threads: 线程
|
|
68
|
-
Jobs:
|
|
73
|
+
Jobs: 任务
|
|
74
|
+
Paused: 已暫停
|
|
75
|
+
Stop: 強制暫停
|
|
76
|
+
Quiet: 暫停
|
|
77
|
+
StopAll: 全部強制暫停
|
|
78
|
+
QuietAll: 全部暫停
|
|
79
|
+
PollingInterval: 輪詢週期
|
|
80
|
+
Plugins: 套件
|
|
81
|
+
NotYetEnqueued: 尚未進入佇列
|
|
82
|
+
CreatedAt: 建立時間
|
|
83
|
+
BackToApp: 回首頁
|
|
84
|
+
Latency: 延時
|
|
85
|
+
Pause: 暫停
|
|
86
|
+
Unpause: 取消暂停
|
|
87
|
+
Metrics: 指标
|
|
88
|
+
NoDataFound: 无数据
|
|
89
|
+
TotalExecutionTime: 总执行时间
|
|
90
|
+
AvgExecutionTime: 平均执行时间
|
|
91
|
+
Context: 上下文
|
|
92
|
+
Bucket: 桶
|
|
93
|
+
NoJobMetricsFound: 无任务相关指标数据
|
data/web/locales/zh-tw.yml
CHANGED
|
@@ -7,6 +7,7 @@ zh-tw: # <---- change this to your locale code
|
|
|
7
7
|
Realtime: 即時
|
|
8
8
|
History: 歷史資料
|
|
9
9
|
Busy: 忙碌
|
|
10
|
+
Utilization: 使用率
|
|
10
11
|
Processed: 已處理
|
|
11
12
|
Failed: 已失敗
|
|
12
13
|
Scheduled: 已排程
|
|
@@ -25,26 +26,28 @@ zh-tw: # <---- change this to your locale code
|
|
|
25
26
|
CurrentMessagesInQueue: 目前在<span class='title'>%{queue}</span>的工作
|
|
26
27
|
Delete: 刪除
|
|
27
28
|
AddToQueue: 增加至佇列
|
|
28
|
-
AreYouSureDeleteJob:
|
|
29
|
-
AreYouSureDeleteQueue:
|
|
29
|
+
AreYouSureDeleteJob: 確定要刪除這個工作嗎?
|
|
30
|
+
AreYouSureDeleteQueue: 確定要刪除%{queue}佇列?這會刪除佇列裡的所有工作,佇列將會在有新工作時重新出現。
|
|
30
31
|
Queues: 佇列
|
|
31
32
|
Size: 容量
|
|
32
33
|
Actions: 動作
|
|
33
34
|
NextRetry: 下次重試
|
|
34
35
|
RetryCount: 重試次數
|
|
35
36
|
RetryNow: 馬上重試
|
|
37
|
+
Kill: 取消
|
|
36
38
|
LastRetry: 最後一次重試
|
|
37
39
|
OriginallyFailed: 原本已失敗
|
|
38
40
|
AreYouSure: 你確定?
|
|
39
|
-
DeleteAll:
|
|
40
|
-
RetryAll:
|
|
41
|
-
|
|
41
|
+
DeleteAll: 全部刪除
|
|
42
|
+
RetryAll: 全部重試
|
|
43
|
+
KillAll: 全部取消
|
|
44
|
+
NoRetriesFound: 找無可重試的工作
|
|
42
45
|
Error: 錯誤
|
|
43
46
|
ErrorClass: 錯誤類別
|
|
44
47
|
ErrorMessage: 錯誤訊息
|
|
45
|
-
ErrorBacktrace:
|
|
48
|
+
ErrorBacktrace: 詳細錯誤訊息
|
|
46
49
|
GoBack: ← 返回
|
|
47
|
-
NoScheduledFound:
|
|
50
|
+
NoScheduledFound: 找無已排程的工作
|
|
48
51
|
When: 當
|
|
49
52
|
ScheduledJobs: 已排程的工作
|
|
50
53
|
idle: 閒置
|
|
@@ -62,7 +65,29 @@ zh-tw: # <---- change this to your locale code
|
|
|
62
65
|
DeadJobs: 停滯工作
|
|
63
66
|
NoDeadJobsFound: 沒有發現任何停滯的工作
|
|
64
67
|
Dead: 停滯
|
|
68
|
+
Process: 程序
|
|
65
69
|
Processes: 處理中
|
|
70
|
+
Name: 名稱
|
|
66
71
|
Thread: 執行緒
|
|
67
72
|
Threads: 執行緒
|
|
68
73
|
Jobs: 工作
|
|
74
|
+
Paused: 已暫停
|
|
75
|
+
Stop: 強制暫停
|
|
76
|
+
Quiet: 暫停
|
|
77
|
+
StopAll: 全部強制暫停
|
|
78
|
+
QuietAll: 全部暫停
|
|
79
|
+
PollingInterval: 輪詢週期
|
|
80
|
+
Plugins: 套件
|
|
81
|
+
NotYetEnqueued: 尚未進入佇列
|
|
82
|
+
CreatedAt: 建立時間
|
|
83
|
+
BackToApp: 回首頁
|
|
84
|
+
Latency: 延時
|
|
85
|
+
Pause: 暫停
|
|
86
|
+
Unpause: 取消暫停
|
|
87
|
+
Metrics: 計量
|
|
88
|
+
NoDataFound: 找無資料
|
|
89
|
+
TotalExecutionTime: 總執行時間
|
|
90
|
+
AvgExecutionTime: 平均執行時間
|
|
91
|
+
Context: 上下文
|
|
92
|
+
Bucket: 桶
|
|
93
|
+
NoJobMetricsFound: 找無工作相關計量資料
|
data/web/views/busy.erb
CHANGED
|
@@ -96,6 +96,11 @@
|
|
|
96
96
|
<div class="col-sm-7">
|
|
97
97
|
<h3><%= t('Jobs') %></h3>
|
|
98
98
|
</div>
|
|
99
|
+
<% if @workset.size > 0 && @total_size > @count %>
|
|
100
|
+
<div class="col-sm-4">
|
|
101
|
+
<%= erb :_paging, locals: { url: "#{root_path}busy" } %>
|
|
102
|
+
</div>
|
|
103
|
+
<% end %>
|
|
99
104
|
</div>
|
|
100
105
|
|
|
101
106
|
<div class="table_container">
|
|
@@ -109,7 +114,7 @@
|
|
|
109
114
|
<th><%= t('Arguments') %></th>
|
|
110
115
|
<th><%= t('Started') %></th>
|
|
111
116
|
</thead>
|
|
112
|
-
<% workset.each do |process, thread, msg| %>
|
|
117
|
+
<% @workset.each do |process, thread, msg| %>
|
|
113
118
|
<% job = Sidekiq::JobRecord.new(msg['payload']) %>
|
|
114
119
|
<tr>
|
|
115
120
|
<td><%= process %></td>
|
metadata
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sidekiq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.5.
|
|
4
|
+
version: 6.5.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Perham
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-10-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
+
- - "<"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5'
|
|
17
20
|
- - ">="
|
|
18
21
|
- !ruby/object:Gem::Version
|
|
19
22
|
version: 4.5.0
|
|
@@ -21,6 +24,9 @@ dependencies:
|
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
27
|
+
- - "<"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '5'
|
|
24
30
|
- - ">="
|
|
25
31
|
- !ruby/object:Gem::Version
|
|
26
32
|
version: 4.5.0
|
|
@@ -28,16 +34,22 @@ dependencies:
|
|
|
28
34
|
name: connection_pool
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
30
36
|
requirements:
|
|
37
|
+
- - "<"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3'
|
|
31
40
|
- - ">="
|
|
32
41
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 2.2.
|
|
42
|
+
version: 2.2.5
|
|
34
43
|
type: :runtime
|
|
35
44
|
prerelease: false
|
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
46
|
requirements:
|
|
47
|
+
- - "<"
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '3'
|
|
38
50
|
- - ">="
|
|
39
51
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 2.2.
|
|
52
|
+
version: 2.2.5
|
|
41
53
|
- !ruby/object:Gem::Dependency
|
|
42
54
|
name: rack
|
|
43
55
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -206,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
206
218
|
- !ruby/object:Gem::Version
|
|
207
219
|
version: '0'
|
|
208
220
|
requirements: []
|
|
209
|
-
rubygems_version: 3.
|
|
221
|
+
rubygems_version: 3.4.20
|
|
210
222
|
signing_key:
|
|
211
223
|
specification_version: 4
|
|
212
224
|
summary: Simple, efficient background processing for Ruby
|