sidekiq 6.0.0 → 6.3.0
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.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +258 -2
- data/LICENSE +1 -1
- data/README.md +6 -8
- data/bin/sidekiq +26 -2
- data/bin/sidekiqload +8 -4
- data/bin/sidekiqmon +4 -5
- data/lib/generators/sidekiq/worker_generator.rb +11 -1
- data/lib/sidekiq/api.rb +220 -145
- data/lib/sidekiq/cli.rb +64 -27
- data/lib/sidekiq/client.rb +31 -14
- data/lib/sidekiq/extensions/action_mailer.rb +3 -2
- data/lib/sidekiq/extensions/active_record.rb +4 -3
- data/lib/sidekiq/extensions/class_methods.rb +5 -4
- data/lib/sidekiq/extensions/generic_proxy.rb +3 -1
- data/lib/sidekiq/fetch.rb +36 -27
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +13 -5
- data/lib/sidekiq/job_retry.rb +27 -17
- data/lib/sidekiq/launcher.rb +110 -28
- data/lib/sidekiq/logger.rb +109 -12
- data/lib/sidekiq/manager.rb +4 -4
- data/lib/sidekiq/middleware/chain.rb +17 -6
- data/lib/sidekiq/middleware/current_attributes.rb +48 -0
- data/lib/sidekiq/monitor.rb +3 -18
- data/lib/sidekiq/paginator.rb +7 -2
- data/lib/sidekiq/processor.rb +22 -24
- data/lib/sidekiq/rails.rb +27 -18
- data/lib/sidekiq/redis_connection.rb +19 -13
- data/lib/sidekiq/scheduled.rb +37 -11
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing.rb +14 -4
- data/lib/sidekiq/util.rb +28 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +2 -2
- data/lib/sidekiq/web/application.rb +37 -30
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +51 -33
- data/lib/sidekiq/web/router.rb +6 -5
- data/lib/sidekiq/web.rb +37 -73
- data/lib/sidekiq/worker.rb +78 -14
- data/lib/sidekiq.rb +24 -8
- data/sidekiq.gemspec +13 -6
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +83 -64
- data/web/assets/javascripts/dashboard.js +53 -53
- data/web/assets/stylesheets/application-dark.css +147 -0
- data/web/assets/stylesheets/application-rtl.css +0 -4
- data/web/assets/stylesheets/application.css +43 -230
- data/web/locales/ar.yml +8 -2
- data/web/locales/de.yml +14 -2
- data/web/locales/en.yml +6 -1
- data/web/locales/es.yml +18 -2
- data/web/locales/fr.yml +10 -3
- data/web/locales/ja.yml +5 -0
- data/web/locales/lt.yml +83 -0
- data/web/locales/pl.yml +4 -4
- data/web/locales/ru.yml +4 -0
- data/web/locales/vi.yml +83 -0
- data/web/views/_footer.erb +1 -1
- data/web/views/_job_info.erb +3 -2
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +54 -20
- data/web/views/dashboard.erb +22 -14
- data/web/views/dead.erb +3 -3
- data/web/views/layout.erb +3 -1
- data/web/views/morgue.erb +9 -6
- data/web/views/queue.erb +19 -10
- data/web/views/queues.erb +10 -2
- data/web/views/retries.erb +11 -8
- data/web/views/retry.erb +3 -3
- data/web/views/scheduled.erb +5 -2
- metadata +29 -50
- data/.circleci/config.yml +0 -61
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -13
- data/.standard.yml +0 -20
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/6.0-Upgrade.md +0 -70
- data/COMM-LICENSE +0 -97
- data/Ent-2.0-Upgrade.md +0 -37
- data/Ent-Changes.md +0 -250
- data/Gemfile +0 -24
- data/Gemfile.lock +0 -196
- 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-5.0-Upgrade.md +0 -25
- data/Pro-Changes.md +0 -768
- data/Rakefile +0 -10
- data/code_of_conduct.md +0 -50
data/lib/sidekiq/launcher.rb
CHANGED
@@ -16,12 +16,13 @@ module Sidekiq
|
|
16
16
|
proc { Sidekiq::VERSION },
|
17
17
|
proc { |me, data| data["tag"] },
|
18
18
|
proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data["concurrency"]} busy]" },
|
19
|
-
proc { |me, data| "stopping" if me.stopping? }
|
19
|
+
proc { |me, data| "stopping" if me.stopping? }
|
20
20
|
]
|
21
21
|
|
22
22
|
attr_accessor :manager, :poller, :fetcher
|
23
23
|
|
24
24
|
def initialize(options)
|
25
|
+
options[:fetch] ||= BasicFetch.new(options)
|
25
26
|
@manager = Sidekiq::Manager.new(options)
|
26
27
|
@poller = Sidekiq::Scheduled::Poller.new
|
27
28
|
@done = false
|
@@ -56,7 +57,7 @@ module Sidekiq
|
|
56
57
|
|
57
58
|
# Requeue everything in case there was a worker who grabbed work while stopped
|
58
59
|
# This call is a no-op in Sidekiq but necessary for Sidekiq Pro.
|
59
|
-
strategy =
|
60
|
+
strategy = @options[:fetch]
|
60
61
|
strategy.bulk_requeue([], @options)
|
61
62
|
|
62
63
|
clear_heartbeat
|
@@ -68,10 +69,12 @@ module Sidekiq
|
|
68
69
|
|
69
70
|
private unless $TESTING
|
70
71
|
|
72
|
+
BEAT_PAUSE = 5
|
73
|
+
|
71
74
|
def start_heartbeat
|
72
75
|
loop do
|
73
76
|
heartbeat
|
74
|
-
sleep
|
77
|
+
sleep BEAT_PAUSE
|
75
78
|
end
|
76
79
|
Sidekiq.logger.info("Heartbeat stopping...")
|
77
80
|
end
|
@@ -83,7 +86,7 @@ module Sidekiq
|
|
83
86
|
Sidekiq.redis do |conn|
|
84
87
|
conn.pipelined do
|
85
88
|
conn.srem("processes", identity)
|
86
|
-
conn.
|
89
|
+
conn.unlink("#{identity}:workers")
|
87
90
|
end
|
88
91
|
end
|
89
92
|
rescue
|
@@ -96,6 +99,32 @@ module Sidekiq
|
|
96
99
|
❤
|
97
100
|
end
|
98
101
|
|
102
|
+
def self.flush_stats
|
103
|
+
fails = Processor::FAILURE.reset
|
104
|
+
procd = Processor::PROCESSED.reset
|
105
|
+
return if fails + procd == 0
|
106
|
+
|
107
|
+
nowdate = Time.now.utc.strftime("%Y-%m-%d")
|
108
|
+
begin
|
109
|
+
Sidekiq.redis do |conn|
|
110
|
+
conn.pipelined do
|
111
|
+
conn.incrby("stat:processed", procd)
|
112
|
+
conn.incrby("stat:processed:#{nowdate}", procd)
|
113
|
+
conn.expire("stat:processed:#{nowdate}", STATS_TTL)
|
114
|
+
|
115
|
+
conn.incrby("stat:failed", fails)
|
116
|
+
conn.incrby("stat:failed:#{nowdate}", fails)
|
117
|
+
conn.expire("stat:failed:#{nowdate}", STATS_TTL)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
rescue => ex
|
121
|
+
# we're exiting the process, things might be shut down so don't
|
122
|
+
# try to handle the exception
|
123
|
+
Sidekiq.logger.warn("Unable to flush stats: #{ex}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
at_exit(&method(:flush_stats))
|
127
|
+
|
99
128
|
def ❤
|
100
129
|
key = identity
|
101
130
|
fails = procd = 0
|
@@ -118,7 +147,7 @@ module Sidekiq
|
|
118
147
|
conn.incrby("stat:failed:#{nowdate}", fails)
|
119
148
|
conn.expire("stat:failed:#{nowdate}", STATS_TTL)
|
120
149
|
|
121
|
-
conn.
|
150
|
+
conn.unlink(workers_key)
|
122
151
|
curstate.each_pair do |tid, hash|
|
123
152
|
conn.hset(workers_key, tid, Sidekiq.dump_json(hash))
|
124
153
|
end
|
@@ -126,18 +155,24 @@ module Sidekiq
|
|
126
155
|
end
|
127
156
|
end
|
128
157
|
|
158
|
+
rtt = check_rtt
|
159
|
+
|
129
160
|
fails = procd = 0
|
161
|
+
kb = memory_usage(::Process.pid)
|
130
162
|
|
131
163
|
_, exists, _, _, msg = Sidekiq.redis { |conn|
|
132
|
-
|
164
|
+
conn.multi {
|
133
165
|
conn.sadd("processes", key)
|
134
|
-
conn.exists(key)
|
135
|
-
conn.hmset(key, "info", to_json,
|
166
|
+
conn.exists?(key)
|
167
|
+
conn.hmset(key, "info", to_json,
|
168
|
+
"busy", curstate.size,
|
169
|
+
"beat", Time.now.to_f,
|
170
|
+
"rtt_us", rtt,
|
171
|
+
"quiet", @done,
|
172
|
+
"rss", kb)
|
136
173
|
conn.expire(key, 60)
|
137
174
|
conn.rpop("#{key}-signals")
|
138
175
|
}
|
139
|
-
|
140
|
-
res
|
141
176
|
}
|
142
177
|
|
143
178
|
# first heartbeat or recovering from an outage and need to reestablish our heartbeat
|
@@ -148,34 +183,81 @@ module Sidekiq
|
|
148
183
|
::Process.kill(msg, ::Process.pid)
|
149
184
|
rescue => e
|
150
185
|
# ignore all redis/network issues
|
151
|
-
logger.error("heartbeat: #{e
|
186
|
+
logger.error("heartbeat: #{e}")
|
152
187
|
# don't lose the counts if there was a network issue
|
153
188
|
Processor::PROCESSED.incr(procd)
|
154
189
|
Processor::FAILURE.incr(fails)
|
155
190
|
end
|
156
191
|
end
|
157
192
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
193
|
+
# We run the heartbeat every five seconds.
|
194
|
+
# Capture five samples of RTT, log a warning if each sample
|
195
|
+
# is above our warning threshold.
|
196
|
+
RTT_READINGS = RingBuffer.new(5)
|
197
|
+
RTT_WARNING_LEVEL = 50_000
|
198
|
+
|
199
|
+
def check_rtt
|
200
|
+
a = b = 0
|
201
|
+
Sidekiq.redis do |x|
|
202
|
+
a = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
203
|
+
x.ping
|
204
|
+
b = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
205
|
+
end
|
206
|
+
rtt = b - a
|
207
|
+
RTT_READINGS << rtt
|
208
|
+
# Ideal RTT for Redis is < 1000µs
|
209
|
+
# Workable is < 10,000µs
|
210
|
+
# Log a warning if it's a disaster.
|
211
|
+
if RTT_READINGS.all? { |x| x > RTT_WARNING_LEVEL }
|
212
|
+
Sidekiq.logger.warn <<~EOM
|
213
|
+
Your Redis network connection is performing extremely poorly.
|
214
|
+
Last RTT readings were #{RTT_READINGS.buffer.inspect}, ideally these should be < 1000.
|
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
|
218
|
+
EOM
|
219
|
+
RTT_READINGS.reset
|
170
220
|
end
|
221
|
+
rtt
|
222
|
+
end
|
223
|
+
|
224
|
+
MEMORY_GRABBER = case RUBY_PLATFORM
|
225
|
+
when /linux/
|
226
|
+
->(pid) {
|
227
|
+
IO.readlines("/proc/#{$$}/status").each do |line|
|
228
|
+
next unless line.start_with?("VmRSS:")
|
229
|
+
break line.split[1].to_i
|
230
|
+
end
|
231
|
+
}
|
232
|
+
when /darwin|bsd/
|
233
|
+
->(pid) {
|
234
|
+
`ps -o pid,rss -p #{pid}`.lines.last.split.last.to_i
|
235
|
+
}
|
236
|
+
else
|
237
|
+
->(pid) { 0 }
|
238
|
+
end
|
239
|
+
|
240
|
+
def memory_usage(pid)
|
241
|
+
MEMORY_GRABBER.call(pid)
|
242
|
+
end
|
243
|
+
|
244
|
+
def to_data
|
245
|
+
@data ||= {
|
246
|
+
"hostname" => hostname,
|
247
|
+
"started_at" => Time.now.to_f,
|
248
|
+
"pid" => ::Process.pid,
|
249
|
+
"tag" => @options[:tag] || "",
|
250
|
+
"concurrency" => @options[:concurrency],
|
251
|
+
"queues" => @options[:queues].uniq,
|
252
|
+
"labels" => @options[:labels],
|
253
|
+
"identity" => identity
|
254
|
+
}
|
171
255
|
end
|
172
256
|
|
173
257
|
def to_json
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
Sidekiq.dump_json(to_data)
|
178
|
-
end
|
258
|
+
# this data changes infrequently so dump it to a string
|
259
|
+
# now so we don't need to dump it every heartbeat.
|
260
|
+
@json ||= Sidekiq.dump_json(to_data)
|
179
261
|
end
|
180
262
|
end
|
181
263
|
end
|
data/lib/sidekiq/logger.rb
CHANGED
@@ -4,22 +4,110 @@ require "logger"
|
|
4
4
|
require "time"
|
5
5
|
|
6
6
|
module Sidekiq
|
7
|
-
|
8
|
-
def
|
9
|
-
|
7
|
+
module Context
|
8
|
+
def self.with(hash)
|
9
|
+
orig_context = current.dup
|
10
|
+
current.merge!(hash)
|
11
|
+
yield
|
12
|
+
ensure
|
13
|
+
Thread.current[:sidekiq_context] = orig_context
|
14
|
+
end
|
10
15
|
|
11
|
-
|
16
|
+
def self.current
|
17
|
+
Thread.current[:sidekiq_context] ||= {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module LoggingUtils
|
22
|
+
LEVELS = {
|
23
|
+
"debug" => 0,
|
24
|
+
"info" => 1,
|
25
|
+
"warn" => 2,
|
26
|
+
"error" => 3,
|
27
|
+
"fatal" => 4
|
28
|
+
}
|
29
|
+
LEVELS.default_proc = proc do |_, level|
|
30
|
+
Sidekiq.logger.warn("Invalid log level: #{level.inspect}")
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug?
|
35
|
+
level <= 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def info?
|
39
|
+
level <= 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def warn?
|
43
|
+
level <= 2
|
44
|
+
end
|
45
|
+
|
46
|
+
def error?
|
47
|
+
level <= 3
|
48
|
+
end
|
49
|
+
|
50
|
+
def fatal?
|
51
|
+
level <= 4
|
12
52
|
end
|
13
53
|
|
14
|
-
def
|
15
|
-
|
54
|
+
def local_level
|
55
|
+
Thread.current[:sidekiq_log_level]
|
56
|
+
end
|
57
|
+
|
58
|
+
def local_level=(level)
|
59
|
+
case level
|
60
|
+
when Integer
|
61
|
+
Thread.current[:sidekiq_log_level] = level
|
62
|
+
when Symbol, String
|
63
|
+
Thread.current[:sidekiq_log_level] = LEVELS[level.to_s]
|
64
|
+
when nil
|
65
|
+
Thread.current[:sidekiq_log_level] = nil
|
66
|
+
else
|
67
|
+
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def level
|
72
|
+
local_level || super
|
73
|
+
end
|
74
|
+
|
75
|
+
# Change the thread-local level for the duration of the given block.
|
76
|
+
def log_at(level)
|
77
|
+
old_local_level = local_level
|
78
|
+
self.local_level = level
|
16
79
|
yield
|
17
80
|
ensure
|
18
|
-
|
81
|
+
self.local_level = old_local_level
|
19
82
|
end
|
20
83
|
|
21
|
-
|
22
|
-
|
84
|
+
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
85
|
+
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
86
|
+
def add(severity, message = nil, progname = nil, &block)
|
87
|
+
severity ||= ::Logger::UNKNOWN
|
88
|
+
progname ||= @progname
|
89
|
+
|
90
|
+
return true if @logdev.nil? || severity < level
|
91
|
+
|
92
|
+
if message.nil?
|
93
|
+
if block
|
94
|
+
message = yield
|
95
|
+
else
|
96
|
+
message = progname
|
97
|
+
progname = @progname
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
@logdev.write format_message(format_severity(severity), Time.now, progname, message)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Logger < ::Logger
|
106
|
+
include LoggingUtils
|
107
|
+
|
108
|
+
def initialize(*args, **kwargs)
|
109
|
+
super
|
110
|
+
self.formatter = Sidekiq.log_formatter
|
23
111
|
end
|
24
112
|
|
25
113
|
module Formatters
|
@@ -29,11 +117,20 @@ module Sidekiq
|
|
29
117
|
end
|
30
118
|
|
31
119
|
def ctx
|
32
|
-
|
120
|
+
Sidekiq::Context.current
|
33
121
|
end
|
34
122
|
|
35
123
|
def format_context
|
36
|
-
|
124
|
+
if ctx.any?
|
125
|
+
" " + ctx.compact.map { |k, v|
|
126
|
+
case v
|
127
|
+
when Array
|
128
|
+
"#{k}=#{v.join(",")}"
|
129
|
+
else
|
130
|
+
"#{k}=#{v}"
|
131
|
+
end
|
132
|
+
}.join(" ")
|
133
|
+
end
|
37
134
|
end
|
38
135
|
end
|
39
136
|
|
@@ -56,7 +153,7 @@ module Sidekiq
|
|
56
153
|
pid: ::Process.pid,
|
57
154
|
tid: tid,
|
58
155
|
lvl: severity,
|
59
|
-
msg: message
|
156
|
+
msg: message
|
60
157
|
}
|
61
158
|
c = ctx
|
62
159
|
hash["ctx"] = c unless c.empty?
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -35,7 +35,7 @@ module Sidekiq
|
|
35
35
|
@done = false
|
36
36
|
@workers = Set.new
|
37
37
|
@count.times do
|
38
|
-
@workers << Processor.new(self)
|
38
|
+
@workers << Processor.new(self, options)
|
39
39
|
end
|
40
40
|
@plock = Mutex.new
|
41
41
|
end
|
@@ -56,7 +56,7 @@ module Sidekiq
|
|
56
56
|
end
|
57
57
|
|
58
58
|
# hack for quicker development / testing environment #2774
|
59
|
-
PAUSE_TIME =
|
59
|
+
PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
|
60
60
|
|
61
61
|
def stop(deadline)
|
62
62
|
quiet
|
@@ -90,7 +90,7 @@ module Sidekiq
|
|
90
90
|
@plock.synchronize do
|
91
91
|
@workers.delete(processor)
|
92
92
|
unless @done
|
93
|
-
p = Processor.new(self)
|
93
|
+
p = Processor.new(self, options)
|
94
94
|
@workers << p
|
95
95
|
p.start
|
96
96
|
end
|
@@ -123,7 +123,7 @@ module Sidekiq
|
|
123
123
|
# contract says that jobs are run AT LEAST once. Process termination
|
124
124
|
# is delayed until we're certain the jobs are back in Redis because
|
125
125
|
# it is worse to lose a job than to run it twice.
|
126
|
-
strategy =
|
126
|
+
strategy = @options[:fetch]
|
127
127
|
strategy.bulk_requeue(jobs, @options)
|
128
128
|
end
|
129
129
|
|
@@ -67,7 +67,6 @@ module Sidekiq
|
|
67
67
|
module Middleware
|
68
68
|
class Chain
|
69
69
|
include Enumerable
|
70
|
-
attr_reader :entries
|
71
70
|
|
72
71
|
def initialize_copy(copy)
|
73
72
|
copy.instance_variable_set(:@entries, entries.dup)
|
@@ -78,21 +77,25 @@ module Sidekiq
|
|
78
77
|
end
|
79
78
|
|
80
79
|
def initialize
|
81
|
-
@entries =
|
80
|
+
@entries = nil
|
82
81
|
yield self if block_given?
|
83
82
|
end
|
84
83
|
|
84
|
+
def entries
|
85
|
+
@entries ||= []
|
86
|
+
end
|
87
|
+
|
85
88
|
def remove(klass)
|
86
89
|
entries.delete_if { |entry| entry.klass == klass }
|
87
90
|
end
|
88
91
|
|
89
92
|
def add(klass, *args)
|
90
|
-
remove(klass)
|
93
|
+
remove(klass)
|
91
94
|
entries << Entry.new(klass, *args)
|
92
95
|
end
|
93
96
|
|
94
97
|
def prepend(klass, *args)
|
95
|
-
remove(klass)
|
98
|
+
remove(klass)
|
96
99
|
entries.insert(0, Entry.new(klass, *args))
|
97
100
|
end
|
98
101
|
|
@@ -114,6 +117,10 @@ module Sidekiq
|
|
114
117
|
any? { |entry| entry.klass == klass }
|
115
118
|
end
|
116
119
|
|
120
|
+
def empty?
|
121
|
+
@entries.nil? || @entries.empty?
|
122
|
+
end
|
123
|
+
|
117
124
|
def retrieve
|
118
125
|
map(&:make_new)
|
119
126
|
end
|
@@ -123,8 +130,10 @@ module Sidekiq
|
|
123
130
|
end
|
124
131
|
|
125
132
|
def invoke(*args)
|
126
|
-
|
127
|
-
|
133
|
+
return yield if empty?
|
134
|
+
|
135
|
+
chain = retrieve
|
136
|
+
traverse_chain = proc do
|
128
137
|
if chain.empty?
|
129
138
|
yield
|
130
139
|
else
|
@@ -135,6 +144,8 @@ module Sidekiq
|
|
135
144
|
end
|
136
145
|
end
|
137
146
|
|
147
|
+
private
|
148
|
+
|
138
149
|
class Entry
|
139
150
|
attr_reader :klass
|
140
151
|
|
@@ -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/monitor.rb
CHANGED
@@ -4,21 +4,6 @@ require "fileutils"
|
|
4
4
|
require "sidekiq/api"
|
5
5
|
|
6
6
|
class Sidekiq::Monitor
|
7
|
-
CMD = File.basename($PROGRAM_NAME)
|
8
|
-
|
9
|
-
attr_reader :stage
|
10
|
-
|
11
|
-
def self.print_usage
|
12
|
-
puts "#{CMD} - monitor Sidekiq from the command line."
|
13
|
-
puts
|
14
|
-
puts "Usage: #{CMD} status <section>"
|
15
|
-
puts
|
16
|
-
puts " <section> (optional) view a specific section of the status output"
|
17
|
-
puts " Valid sections are: #{Sidekiq::Monitor::Status::VALID_SECTIONS.join(", ")}"
|
18
|
-
puts
|
19
|
-
puts "Set REDIS_URL to the location of your Redis server if not monitoring localhost."
|
20
|
-
end
|
21
|
-
|
22
7
|
class Status
|
23
8
|
VALID_SECTIONS = %w[all version overview processes queues]
|
24
9
|
COL_PAD = 2
|
@@ -47,7 +32,7 @@ class Sidekiq::Monitor
|
|
47
32
|
|
48
33
|
def version
|
49
34
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
50
|
-
puts Time.now
|
35
|
+
puts Time.now.utc
|
51
36
|
end
|
52
37
|
|
53
38
|
def overview
|
@@ -77,7 +62,7 @@ class Sidekiq::Monitor
|
|
77
62
|
columns = {
|
78
63
|
name: [:ljust, (["name"] + queue_data.map(&:name)).map(&:length).max + COL_PAD],
|
79
64
|
size: [:rjust, (["size"] + queue_data.map(&:size)).map(&:length).max + COL_PAD],
|
80
|
-
latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
|
65
|
+
latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
|
81
66
|
}
|
82
67
|
columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) }
|
83
68
|
puts
|
@@ -116,7 +101,7 @@ class Sidekiq::Monitor
|
|
116
101
|
tags = [
|
117
102
|
process["tag"],
|
118
103
|
process["labels"],
|
119
|
-
(process["quiet"] == "true" ? "quiet" : nil)
|
104
|
+
(process["quiet"] == "true" ? "quiet" : nil)
|
120
105
|
].flatten.compact
|
121
106
|
tags.any? ? "[#{tags.join("] [")}]" : nil
|
122
107
|
end
|
data/lib/sidekiq/paginator.rb
CHANGED
@@ -12,10 +12,10 @@ 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
18
|
when "zset"
|
18
|
-
rev = opts && opts[:reverse]
|
19
19
|
total_size, items = conn.multi {
|
20
20
|
conn.zcard(key)
|
21
21
|
if rev
|
@@ -28,8 +28,13 @@ module Sidekiq
|
|
28
28
|
when "list"
|
29
29
|
total_size, items = conn.multi {
|
30
30
|
conn.llen(key)
|
31
|
-
|
31
|
+
if rev
|
32
|
+
conn.lrange(key, -ending - 1, -starting - 1)
|
33
|
+
else
|
34
|
+
conn.lrange(key, starting, ending)
|
35
|
+
end
|
32
36
|
}
|
37
|
+
items.reverse! if rev
|
33
38
|
[current_page, total_size, items]
|
34
39
|
when "none"
|
35
40
|
[1, 0, []]
|