sidekiq 5.1.1 → 7.1.2
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 +5 -5
- data/Changes.md +627 -8
- data/LICENSE.txt +9 -0
- data/README.md +47 -50
- data/bin/sidekiq +22 -3
- data/bin/sidekiqload +213 -115
- data/bin/sidekiqmon +11 -0
- data/lib/generators/sidekiq/job_generator.rb +57 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
- data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
- data/lib/sidekiq/api.rb +566 -329
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +241 -256
- data/lib/sidekiq/client.rb +125 -102
- data/lib/sidekiq/component.rb +68 -0
- data/lib/sidekiq/config.rb +278 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +49 -42
- data/lib/sidekiq/job.rb +374 -0
- data/lib/sidekiq/job_logger.rb +36 -9
- data/lib/sidekiq/job_retry.rb +147 -98
- data/lib/sidekiq/job_util.rb +105 -0
- data/lib/sidekiq/launcher.rb +207 -103
- data/lib/sidekiq/logger.rb +131 -0
- data/lib/sidekiq/manager.rb +43 -47
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +136 -0
- data/lib/sidekiq/middleware/chain.rb +113 -56
- data/lib/sidekiq/middleware/current_attributes.rb +95 -0
- data/lib/sidekiq/middleware/i18n.rb +7 -7
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +146 -0
- data/lib/sidekiq/paginator.rb +28 -16
- data/lib/sidekiq/processor.rb +159 -107
- data/lib/sidekiq/rails.rb +54 -43
- data/lib/sidekiq/redis_client_adapter.rb +96 -0
- data/lib/sidekiq/redis_connection.rb +39 -81
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +139 -48
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing/inline.rb +6 -5
- data/lib/sidekiq/testing.rb +70 -88
- data/lib/sidekiq/transaction_aware_client.rb +44 -0
- data/lib/sidekiq/version.rb +3 -1
- data/lib/sidekiq/web/action.rb +15 -11
- data/lib/sidekiq/web/application.rb +143 -77
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +144 -106
- data/lib/sidekiq/web/router.rb +23 -19
- data/lib/sidekiq/web.rb +60 -111
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +94 -183
- data/sidekiq.gemspec +25 -23
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +130 -61
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +166 -0
- data/web/assets/javascripts/dashboard.js +36 -282
- data/web/assets/javascripts/metrics.js +264 -0
- data/web/assets/stylesheets/application-dark.css +147 -0
- data/web/assets/stylesheets/application-rtl.css +2 -95
- data/web/assets/stylesheets/application.css +134 -521
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +71 -64
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -53
- data/web/locales/el.yml +43 -24
- data/web/locales/en.yml +84 -65
- data/web/locales/es.yml +70 -54
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +83 -62
- data/web/locales/gd.yml +99 -0
- data/web/locales/he.yml +65 -64
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +53 -53
- data/web/locales/ja.yml +75 -64
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +83 -0
- data/web/locales/nb.yml +61 -61
- data/web/locales/nl.yml +52 -52
- data/web/locales/pl.yml +45 -45
- data/web/locales/pt-br.yml +63 -55
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +68 -63
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/uk.yml +62 -61
- data/web/locales/ur.yml +64 -64
- data/web/locales/vi.yml +83 -0
- data/web/locales/zh-cn.yml +43 -16
- data/web/locales/zh-tw.yml +42 -8
- data/web/views/_footer.erb +8 -2
- data/web/views/_job_info.erb +21 -4
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_nav.erb +4 -18
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +3 -6
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +75 -25
- data/web/views/dashboard.erb +58 -18
- data/web/views/dead.erb +3 -3
- data/web/views/layout.erb +4 -2
- data/web/views/metrics.erb +82 -0
- data/web/views/metrics_for_job.erb +68 -0
- data/web/views/morgue.erb +14 -15
- data/web/views/queue.erb +33 -23
- data/web/views/queues.erb +14 -4
- data/web/views/retries.erb +19 -16
- data/web/views/retry.erb +3 -3
- data/web/views/scheduled.erb +17 -15
- metadata +71 -140
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -13
- data/.travis.yml +0 -14
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/COMM-LICENSE +0 -95
- data/Ent-Changes.md +0 -210
- data/Gemfile +0 -8
- data/LICENSE +0 -9
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-3.0-Upgrade.md +0 -44
- data/Pro-4.0-Upgrade.md +0 -35
- data/Pro-Changes.md +0 -716
- data/Rakefile +0 -8
- data/bin/sidekiqctl +0 -99
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/core_ext.rb +0 -1
- data/lib/sidekiq/delay.rb +0 -41
- data/lib/sidekiq/exception_handler.rb +0 -29
- data/lib/sidekiq/extensions/action_mailer.rb +0 -57
- data/lib/sidekiq/extensions/active_record.rb +0 -40
- data/lib/sidekiq/extensions/class_methods.rb +0 -40
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -31
- data/lib/sidekiq/logging.rb +0 -122
- data/lib/sidekiq/middleware/server/active_record.rb +0 -22
- data/lib/sidekiq/middleware/server/active_record_cache.rb +0 -11
- data/lib/sidekiq/util.rb +0 -66
- data/lib/sidekiq/worker.rb +0 -204
@@ -0,0 +1,95 @@
|
|
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
|
+
# For multiple current attributes, pass an array of current attributes.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # in your initializer
|
15
|
+
# require "sidekiq/middleware/current_attributes"
|
16
|
+
# Sidekiq::CurrentAttributes.persist("Myapp::Current")
|
17
|
+
# # or multiple current attributes
|
18
|
+
# Sidekiq::CurrentAttributes.persist(["Myapp::Current", "Myapp::OtherCurrent"])
|
19
|
+
#
|
20
|
+
module CurrentAttributes
|
21
|
+
class Save
|
22
|
+
include Sidekiq::ClientMiddleware
|
23
|
+
|
24
|
+
def initialize(cattrs)
|
25
|
+
@cattrs = cattrs
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(_, job, _, _)
|
29
|
+
@cattrs.each do |(key, strklass)|
|
30
|
+
if !job.has_key?(key)
|
31
|
+
attrs = strklass.constantize.attributes
|
32
|
+
# Retries can push the job N times, we don't
|
33
|
+
# want retries to reset cattr. #5692, #5090
|
34
|
+
job[key] = attrs if attrs.any?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Load
|
42
|
+
include Sidekiq::ServerMiddleware
|
43
|
+
|
44
|
+
def initialize(cattrs)
|
45
|
+
@cattrs = cattrs
|
46
|
+
end
|
47
|
+
|
48
|
+
def call(_, job, _, &block)
|
49
|
+
cattrs_to_reset = []
|
50
|
+
|
51
|
+
@cattrs.each do |(key, strklass)|
|
52
|
+
if job.has_key?(key)
|
53
|
+
constklass = strklass.constantize
|
54
|
+
cattrs_to_reset << constklass
|
55
|
+
|
56
|
+
job[key].each do |(attribute, value)|
|
57
|
+
constklass.public_send("#{attribute}=", value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
cattrs_to_reset.each(&:reset)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
def persist(klass_or_array, config = Sidekiq.default_configuration)
|
70
|
+
cattrs = build_cattrs_hash(klass_or_array)
|
71
|
+
|
72
|
+
config.client_middleware.add Save, cattrs
|
73
|
+
config.server_middleware.add Load, cattrs
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def build_cattrs_hash(klass_or_array)
|
79
|
+
if klass_or_array.is_a?(Array)
|
80
|
+
{}.tap do |hash|
|
81
|
+
klass_or_array.each_with_index do |klass, index|
|
82
|
+
hash[key_at(index)] = klass.to_s
|
83
|
+
end
|
84
|
+
end
|
85
|
+
else
|
86
|
+
{key_at(0) => klass_or_array.to_s}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def key_at(index)
|
91
|
+
(index == 0) ? "cattr" : "cattr_#{index}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
#
|
3
4
|
# Simple middleware to save the current locale and restore it when the job executes.
|
4
5
|
# Use it by requiring it in your initializer:
|
@@ -9,19 +10,18 @@ module Sidekiq::Middleware::I18n
|
|
9
10
|
# Get the current locale and store it in the message
|
10
11
|
# to be sent to Sidekiq.
|
11
12
|
class Client
|
12
|
-
|
13
|
-
|
13
|
+
include Sidekiq::ClientMiddleware
|
14
|
+
def call(_jobclass, job, _queue, _redis)
|
15
|
+
job["locale"] ||= I18n.locale
|
14
16
|
yield
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
# Pull the msg locale out and set the current thread to use it.
|
19
21
|
class Server
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
ensure
|
24
|
-
I18n.locale = I18n.default_locale
|
22
|
+
include Sidekiq::ServerMiddleware
|
23
|
+
def call(_jobclass, job, _queue, &block)
|
24
|
+
I18n.with_locale(job.fetch("locale", I18n.default_locale), &block)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
# Server-side middleware must import this Module in order
|
3
|
+
# to get access to server resources during `call`.
|
4
|
+
module ServerMiddleware
|
5
|
+
attr_accessor :config
|
6
|
+
def redis_pool
|
7
|
+
config.redis_pool
|
8
|
+
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
config.logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def redis(&block)
|
15
|
+
config.redis(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# no difference for now
|
20
|
+
ClientMiddleware = ServerMiddleware
|
21
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "sidekiq/api"
|
5
|
+
|
6
|
+
class Sidekiq::Monitor
|
7
|
+
class Status
|
8
|
+
VALID_SECTIONS = %w[all version overview processes queues]
|
9
|
+
COL_PAD = 2
|
10
|
+
|
11
|
+
def display(section = nil)
|
12
|
+
section ||= "all"
|
13
|
+
unless VALID_SECTIONS.include? section
|
14
|
+
puts "I don't know how to check the status of '#{section}'!"
|
15
|
+
puts "Try one of these: #{VALID_SECTIONS.join(", ")}"
|
16
|
+
return
|
17
|
+
end
|
18
|
+
send(section)
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
version
|
23
|
+
puts
|
24
|
+
overview
|
25
|
+
puts
|
26
|
+
processes
|
27
|
+
puts
|
28
|
+
queues
|
29
|
+
end
|
30
|
+
|
31
|
+
def version
|
32
|
+
puts "Sidekiq #{Sidekiq::VERSION}"
|
33
|
+
puts Time.now.utc
|
34
|
+
end
|
35
|
+
|
36
|
+
def overview
|
37
|
+
puts "---- Overview ----"
|
38
|
+
puts " Processed: #{delimit stats.processed}"
|
39
|
+
puts " Failed: #{delimit stats.failed}"
|
40
|
+
puts " Busy: #{delimit stats.workers_size}"
|
41
|
+
puts " Enqueued: #{delimit stats.enqueued}"
|
42
|
+
puts " Retries: #{delimit stats.retry_size}"
|
43
|
+
puts " Scheduled: #{delimit stats.scheduled_size}"
|
44
|
+
puts " Dead: #{delimit stats.dead_size}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def processes
|
48
|
+
puts "---- Processes (#{process_set.size}) ----"
|
49
|
+
process_set.each_with_index do |process, index|
|
50
|
+
# Keep compatibility with legacy versions since we don't want to break sidekiqmon during rolling upgrades or downgrades.
|
51
|
+
#
|
52
|
+
# Before:
|
53
|
+
# ["default", "critical"]
|
54
|
+
#
|
55
|
+
# After:
|
56
|
+
# {"default" => 1, "critical" => 10}
|
57
|
+
queues =
|
58
|
+
if process["weights"]
|
59
|
+
process["weights"].sort_by { |queue| queue[0] }.map { |capsule| capsule.map { |name, weight| (weight > 0) ? "#{name}: #{weight}" : name }.join(", ") }
|
60
|
+
else
|
61
|
+
process["queues"].sort
|
62
|
+
end
|
63
|
+
|
64
|
+
puts "#{process["identity"]} #{tags_for(process)}"
|
65
|
+
puts " Started: #{Time.at(process["started_at"])} (#{time_ago(process["started_at"])})"
|
66
|
+
puts " Threads: #{process["concurrency"]} (#{process["busy"]} busy)"
|
67
|
+
puts " Queues: #{split_multiline(queues, pad: 11)}"
|
68
|
+
puts " Version: #{process["version"] || "Unknown"}" if process["version"] != Sidekiq::VERSION
|
69
|
+
puts "" unless (index + 1) == process_set.size
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def queues
|
74
|
+
puts "---- Queues (#{queue_data.size}) ----"
|
75
|
+
columns = {
|
76
|
+
name: [:ljust, (["name"] + queue_data.map(&:name)).map(&:length).max + COL_PAD],
|
77
|
+
size: [:rjust, (["size"] + queue_data.map(&:size)).map(&:length).max + COL_PAD],
|
78
|
+
latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
|
79
|
+
}
|
80
|
+
columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) }
|
81
|
+
puts
|
82
|
+
queue_data.each do |q|
|
83
|
+
columns.each do |col, (dir, width)|
|
84
|
+
print q.send(col).public_send(dir, width)
|
85
|
+
end
|
86
|
+
puts
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def delimit(number)
|
93
|
+
number.to_s.reverse.scan(/.{1,3}/).join(",").reverse
|
94
|
+
end
|
95
|
+
|
96
|
+
def split_multiline(values, opts = {})
|
97
|
+
return "none" unless values
|
98
|
+
pad = opts[:pad] || 0
|
99
|
+
max_length = opts[:max_length] || (80 - pad)
|
100
|
+
out = []
|
101
|
+
line = ""
|
102
|
+
values.each do |value|
|
103
|
+
if (line.length + value.length) > max_length
|
104
|
+
out << line
|
105
|
+
line = " " * pad
|
106
|
+
end
|
107
|
+
line << value + ", "
|
108
|
+
end
|
109
|
+
out << line[0..-3]
|
110
|
+
out.join("\n")
|
111
|
+
end
|
112
|
+
|
113
|
+
def tags_for(process)
|
114
|
+
tags = [
|
115
|
+
process["tag"],
|
116
|
+
process["labels"],
|
117
|
+
((process["quiet"] == "true") ? "quiet" : nil)
|
118
|
+
].flatten.compact
|
119
|
+
tags.any? ? "[#{tags.join("] [")}]" : nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def time_ago(timestamp)
|
123
|
+
seconds = Time.now - Time.at(timestamp)
|
124
|
+
return "just now" if seconds < 60
|
125
|
+
return "a minute ago" if seconds < 120
|
126
|
+
return "#{seconds.floor / 60} minutes ago" if seconds < 3600
|
127
|
+
return "an hour ago" if seconds < 7200
|
128
|
+
"#{seconds.floor / 60 / 60} hours ago"
|
129
|
+
end
|
130
|
+
|
131
|
+
QUEUE_STRUCT = Struct.new(:name, :size, :latency)
|
132
|
+
def queue_data
|
133
|
+
@queue_data ||= Sidekiq::Queue.all.map { |q|
|
134
|
+
QUEUE_STRUCT.new(q.name, q.size.to_s, sprintf("%#.2f", q.latency))
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
def process_set
|
139
|
+
@process_set ||= Sidekiq::ProcessSet.new
|
140
|
+
end
|
141
|
+
|
142
|
+
def stats
|
143
|
+
@stats ||= Sidekiq::Stats.new
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/sidekiq/paginator.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Sidekiq
|
3
4
|
module Paginator
|
4
|
-
|
5
|
-
|
6
|
-
current_page = pageidx.to_i < 1 ? 1 : pageidx.to_i
|
5
|
+
def page(key, pageidx = 1, page_size = 25, opts = nil)
|
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 = []
|
@@ -12,26 +12,31 @@ module Sidekiq
|
|
12
12
|
|
13
13
|
Sidekiq.redis do |conn|
|
14
14
|
type = conn.type(key)
|
15
|
+
rev = opts && opts[:reverse]
|
15
16
|
|
16
17
|
case type
|
17
|
-
when
|
18
|
-
|
19
|
-
|
20
|
-
conn.zcard(key)
|
18
|
+
when "zset"
|
19
|
+
total_size, items = conn.multi { |transaction|
|
20
|
+
transaction.zcard(key)
|
21
21
|
if rev
|
22
|
-
|
22
|
+
transaction.zrange(key, starting, ending, "REV", withscores: true)
|
23
23
|
else
|
24
|
-
|
24
|
+
transaction.zrange(key, starting, ending, withscores: true)
|
25
25
|
end
|
26
|
-
|
26
|
+
}
|
27
27
|
[current_page, total_size, items]
|
28
|
-
when
|
29
|
-
total_size, items = conn.multi
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
when "list"
|
29
|
+
total_size, items = conn.multi { |transaction|
|
30
|
+
transaction.llen(key)
|
31
|
+
if rev
|
32
|
+
transaction.lrange(key, -ending - 1, -starting - 1)
|
33
|
+
else
|
34
|
+
transaction.lrange(key, starting, ending)
|
35
|
+
end
|
36
|
+
}
|
37
|
+
items.reverse! if rev
|
33
38
|
[current_page, total_size, items]
|
34
|
-
when
|
39
|
+
when "none"
|
35
40
|
[1, 0, []]
|
36
41
|
else
|
37
42
|
raise "can't page a #{type}"
|
@@ -39,5 +44,12 @@ module Sidekiq
|
|
39
44
|
end
|
40
45
|
end
|
41
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
|
42
54
|
end
|
43
55
|
end
|