sidekiq 6.0.7 → 6.2.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 +70 -1
- data/README.md +2 -6
- data/bin/sidekiq +7 -2
- data/lib/sidekiq.rb +5 -3
- data/lib/sidekiq/api.rb +28 -10
- data/lib/sidekiq/cli.rb +23 -7
- data/lib/sidekiq/client.rb +16 -11
- 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/fetch.rb +29 -21
- data/lib/sidekiq/job_retry.rb +1 -0
- data/lib/sidekiq/launcher.rb +55 -3
- data/lib/sidekiq/logger.rb +3 -2
- data/lib/sidekiq/manager.rb +4 -4
- data/lib/sidekiq/middleware/chain.rb +1 -1
- data/lib/sidekiq/processor.rb +4 -4
- data/lib/sidekiq/rails.rb +16 -18
- data/lib/sidekiq/redis_connection.rb +15 -12
- data/lib/sidekiq/sd_notify.rb +1 -1
- data/lib/sidekiq/testing.rb +1 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +35 -72
- data/lib/sidekiq/web/application.rb +9 -5
- data/lib/sidekiq/web/csrf_protection.rb +177 -0
- data/lib/sidekiq/web/helpers.rb +26 -8
- data/lib/sidekiq/web/router.rb +5 -2
- data/lib/sidekiq/worker.rb +2 -5
- data/sidekiq.gemspec +11 -4
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +3 -8
- data/web/assets/stylesheets/application-dark.css +71 -33
- data/web/assets/stylesheets/application.css +24 -8
- data/web/locales/fr.yml +1 -1
- data/web/locales/pl.yml +4 -4
- data/web/locales/ru.yml +4 -0
- data/web/views/busy.erb +44 -14
- data/web/views/layout.erb +1 -0
- data/web/views/morgue.erb +1 -1
- data/web/views/queues.erb +1 -1
- data/web/views/retries.erb +1 -1
- data/web/views/scheduled.erb +1 -1
- metadata +17 -45
- data/.circleci/config.yml +0 -60
- 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 -72
- data/COMM-LICENSE +0 -97
- data/Ent-2.0-Upgrade.md +0 -37
- data/Ent-Changes.md +0 -256
- data/Gemfile +0 -24
- data/Gemfile.lock +0 -208
- 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 -782
- data/Rakefile +0 -10
- data/code_of_conduct.md +0 -50
data/lib/sidekiq/job_retry.rb
CHANGED
data/lib/sidekiq/launcher.rb
CHANGED
@@ -22,6 +22,7 @@ module Sidekiq
|
|
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
|
@@ -152,13 +153,21 @@ module Sidekiq
|
|
152
153
|
end
|
153
154
|
end
|
154
155
|
|
156
|
+
rtt = check_rtt
|
157
|
+
|
155
158
|
fails = procd = 0
|
159
|
+
kb = memory_usage(::Process.pid)
|
156
160
|
|
157
161
|
_, exists, _, _, msg = Sidekiq.redis { |conn|
|
158
162
|
conn.multi {
|
159
163
|
conn.sadd("processes", key)
|
160
|
-
conn.exists(key)
|
161
|
-
conn.hmset(key, "info", to_json,
|
164
|
+
conn.exists?(key)
|
165
|
+
conn.hmset(key, "info", to_json,
|
166
|
+
"busy", curstate.size,
|
167
|
+
"beat", Time.now.to_f,
|
168
|
+
"rtt_us", rtt,
|
169
|
+
"quiet", @done,
|
170
|
+
"rss", kb)
|
162
171
|
conn.expire(key, 60)
|
163
172
|
conn.rpop("#{key}-signals")
|
164
173
|
}
|
@@ -179,6 +188,49 @@ module Sidekiq
|
|
179
188
|
end
|
180
189
|
end
|
181
190
|
|
191
|
+
RTT_WARNING_LEVEL = 50_000
|
192
|
+
|
193
|
+
def check_rtt
|
194
|
+
a = b = 0
|
195
|
+
Sidekiq.redis do |x|
|
196
|
+
a = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
197
|
+
x.ping
|
198
|
+
b = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
199
|
+
end
|
200
|
+
rtt = b - a
|
201
|
+
# Ideal RTT for Redis is < 1000µs
|
202
|
+
# Workable is < 10,000µs
|
203
|
+
# Log a warning if it's a disaster.
|
204
|
+
if rtt > RTT_WARNING_LEVEL
|
205
|
+
Sidekiq.logger.warn <<-EOM
|
206
|
+
Your Redis network connection is performing extremely poorly.
|
207
|
+
Current RTT is #{rtt} µs, ideally this should be < 1000.
|
208
|
+
Ensure Redis is running in the same AZ or datacenter as Sidekiq.
|
209
|
+
EOM
|
210
|
+
end
|
211
|
+
rtt
|
212
|
+
end
|
213
|
+
|
214
|
+
MEMORY_GRABBER = case RUBY_PLATFORM
|
215
|
+
when /linux/
|
216
|
+
->(pid) {
|
217
|
+
IO.readlines("/proc/#{$$}/status").each do |line|
|
218
|
+
next unless line.start_with?("VmRSS:")
|
219
|
+
break line.split[1].to_i
|
220
|
+
end
|
221
|
+
}
|
222
|
+
when /darwin|bsd/
|
223
|
+
->(pid) {
|
224
|
+
`ps -o pid,rss -p #{pid}`.lines.last.split.last.to_i
|
225
|
+
}
|
226
|
+
else
|
227
|
+
->(pid) { 0 }
|
228
|
+
end
|
229
|
+
|
230
|
+
def memory_usage(pid)
|
231
|
+
MEMORY_GRABBER.call(pid)
|
232
|
+
end
|
233
|
+
|
182
234
|
def to_data
|
183
235
|
@data ||= begin
|
184
236
|
{
|
data/lib/sidekiq/logger.rb
CHANGED
@@ -6,10 +6,11 @@ require "time"
|
|
6
6
|
module Sidekiq
|
7
7
|
module Context
|
8
8
|
def self.with(hash)
|
9
|
+
orig_context = current.dup
|
9
10
|
current.merge!(hash)
|
10
11
|
yield
|
11
12
|
ensure
|
12
|
-
|
13
|
+
Thread.current[:sidekiq_context] = orig_context
|
13
14
|
end
|
14
15
|
|
15
16
|
def self.current
|
@@ -89,7 +90,7 @@ module Sidekiq
|
|
89
90
|
return true if @logdev.nil? || severity < level
|
90
91
|
|
91
92
|
if message.nil?
|
92
|
-
if
|
93
|
+
if block
|
93
94
|
message = yield
|
94
95
|
else
|
95
96
|
message = progname
|
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
|
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -28,15 +28,15 @@ module Sidekiq
|
|
28
28
|
attr_reader :thread
|
29
29
|
attr_reader :job
|
30
30
|
|
31
|
-
def initialize(mgr)
|
31
|
+
def initialize(mgr, options)
|
32
32
|
@mgr = mgr
|
33
33
|
@down = false
|
34
34
|
@done = false
|
35
35
|
@job = nil
|
36
36
|
@thread = nil
|
37
|
-
@strategy =
|
38
|
-
@reloader =
|
39
|
-
@job_logger = (
|
37
|
+
@strategy = options[:fetch]
|
38
|
+
@reloader = options[:reloader] || proc { |&block| block.call }
|
39
|
+
@job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
|
40
40
|
@retrier = Sidekiq::JobRetry.new
|
41
41
|
end
|
42
42
|
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -4,6 +4,22 @@ require "sidekiq/worker"
|
|
4
4
|
|
5
5
|
module Sidekiq
|
6
6
|
class Rails < ::Rails::Engine
|
7
|
+
class Reloader
|
8
|
+
def initialize(app = ::Rails.application)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
@app.reloader.wrap do
|
14
|
+
yield
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
7
23
|
# By including the Options module, we allow AJs to directly control sidekiq features
|
8
24
|
# via the *sidekiq_options* class method and, for instance, not use AJ's retry system.
|
9
25
|
# AJ retries don't show up in the Sidekiq UI Retries tab, save any error data, can't be
|
@@ -23,8 +39,6 @@ module Sidekiq
|
|
23
39
|
|
24
40
|
# This hook happens after all initializers are run, just before returning
|
25
41
|
# from config/environment.rb back to sidekiq/cli.rb.
|
26
|
-
# We have to add the reloader after initialize to see if cache_classes has
|
27
|
-
# been turned on.
|
28
42
|
#
|
29
43
|
# None of this matters on the client-side, only within the Sidekiq process itself.
|
30
44
|
config.after_initialize do
|
@@ -32,21 +46,5 @@ module Sidekiq
|
|
32
46
|
Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
|
33
47
|
end
|
34
48
|
end
|
35
|
-
|
36
|
-
class Reloader
|
37
|
-
def initialize(app = ::Rails.application)
|
38
|
-
@app = app
|
39
|
-
end
|
40
|
-
|
41
|
-
def call
|
42
|
-
@app.reloader.wrap do
|
43
|
-
yield
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def inspect
|
48
|
-
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
|
49
|
-
end
|
50
|
-
end
|
51
49
|
end
|
52
50
|
end
|
@@ -8,16 +8,14 @@ module Sidekiq
|
|
8
8
|
class RedisConnection
|
9
9
|
class << self
|
10
10
|
def create(options = {})
|
11
|
-
options.
|
12
|
-
options[key.to_sym] = options.delete(key)
|
13
|
-
end
|
11
|
+
symbolized_options = options.transform_keys(&:to_sym)
|
14
12
|
|
15
|
-
if !
|
16
|
-
|
13
|
+
if !symbolized_options[:url] && (u = determine_redis_provider)
|
14
|
+
symbolized_options[:url] = u
|
17
15
|
end
|
18
16
|
|
19
|
-
size = if
|
20
|
-
|
17
|
+
size = if symbolized_options[:size]
|
18
|
+
symbolized_options[:size]
|
21
19
|
elsif Sidekiq.server?
|
22
20
|
# Give ourselves plenty of connections. pool is lazy
|
23
21
|
# so we won't create them until we need them.
|
@@ -30,11 +28,11 @@ module Sidekiq
|
|
30
28
|
|
31
29
|
verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
|
32
30
|
|
33
|
-
pool_timeout =
|
34
|
-
log_info(
|
31
|
+
pool_timeout = symbolized_options[:pool_timeout] || 1
|
32
|
+
log_info(symbolized_options)
|
35
33
|
|
36
34
|
ConnectionPool.new(timeout: pool_timeout, size: size) do
|
37
|
-
build_client(
|
35
|
+
build_client(symbolized_options)
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
@@ -97,7 +95,12 @@ module Sidekiq
|
|
97
95
|
redacted = "REDACTED"
|
98
96
|
|
99
97
|
# deep clone so we can muck with these options all we want
|
100
|
-
|
98
|
+
#
|
99
|
+
# exclude SSL params from dump-and-load because some information isn't
|
100
|
+
# safely dumpable in current Rubies
|
101
|
+
keys = options.keys
|
102
|
+
keys.delete(:ssl_params)
|
103
|
+
scrubbed_options = Marshal.load(Marshal.dump(options.slice(*keys)))
|
101
104
|
if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password
|
102
105
|
uri.password = redacted
|
103
106
|
scrubbed_options[:url] = uri.to_s
|
@@ -124,7 +127,7 @@ module Sidekiq
|
|
124
127
|
# initialization code at all.
|
125
128
|
#
|
126
129
|
p = ENV["REDIS_PROVIDER"]
|
127
|
-
if p && p =~
|
130
|
+
if p && p =~ /:/
|
128
131
|
raise <<~EOM
|
129
132
|
REDIS_PROVIDER should be set to the name of the variable which contains the Redis URL, not a URL itself.
|
130
133
|
Platforms like Heroku will sell addons that publish a *_URL variable. You need to tell Sidekiq with REDIS_PROVIDER, e.g.:
|
data/lib/sidekiq/sd_notify.rb
CHANGED
@@ -85,7 +85,7 @@ module Sidekiq
|
|
85
85
|
notify(FDSTORE, unset_env)
|
86
86
|
end
|
87
87
|
|
88
|
-
# @
|
88
|
+
# @return [Boolean] true if the service manager expects watchdog keep-alive
|
89
89
|
# notification messages to be sent from this process.
|
90
90
|
#
|
91
91
|
# If the $WATCHDOG_USEC environment variable is set,
|
data/lib/sidekiq/testing.rb
CHANGED
@@ -337,7 +337,7 @@ module Sidekiq
|
|
337
337
|
Sidekiq::Extensions::DelayedModel.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedModel)
|
338
338
|
end
|
339
339
|
|
340
|
-
if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test?
|
340
|
+
if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING
|
341
341
|
puts("**************************************************")
|
342
342
|
puts("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.")
|
343
343
|
puts("**************************************************")
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
@@ -10,12 +10,11 @@ require "sidekiq/web/helpers"
|
|
10
10
|
require "sidekiq/web/router"
|
11
11
|
require "sidekiq/web/action"
|
12
12
|
require "sidekiq/web/application"
|
13
|
+
require "sidekiq/web/csrf_protection"
|
13
14
|
|
14
|
-
require "rack/
|
15
|
-
|
15
|
+
require "rack/content_length"
|
16
16
|
require "rack/builder"
|
17
|
-
require "rack/
|
18
|
-
require "rack/session/cookie"
|
17
|
+
require "rack/static"
|
19
18
|
|
20
19
|
module Sidekiq
|
21
20
|
class Web
|
@@ -39,14 +38,6 @@ module Sidekiq
|
|
39
38
|
self
|
40
39
|
end
|
41
40
|
|
42
|
-
def middlewares
|
43
|
-
@middlewares ||= []
|
44
|
-
end
|
45
|
-
|
46
|
-
def use(*middleware_args, &block)
|
47
|
-
middlewares << [middleware_args, block]
|
48
|
-
end
|
49
|
-
|
50
41
|
def default_tabs
|
51
42
|
DEFAULT_TABS
|
52
43
|
end
|
@@ -72,32 +63,45 @@ module Sidekiq
|
|
72
63
|
opts.each { |key| set(key, false) }
|
73
64
|
end
|
74
65
|
|
75
|
-
|
66
|
+
def middlewares
|
67
|
+
@middlewares ||= []
|
68
|
+
end
|
69
|
+
|
70
|
+
def use(*args, &block)
|
71
|
+
middlewares << [args, block]
|
72
|
+
end
|
73
|
+
|
76
74
|
def set(attribute, value)
|
77
75
|
send(:"#{attribute}=", value)
|
78
76
|
end
|
79
77
|
|
80
|
-
|
78
|
+
def sessions=(val)
|
79
|
+
puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def session_secret=(val)
|
83
|
+
puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_accessor :app_url, :redis_pool
|
81
87
|
attr_writer :locales, :views
|
82
88
|
end
|
83
89
|
|
84
90
|
def self.inherited(child)
|
85
91
|
child.app_url = app_url
|
86
|
-
child.session_secret = session_secret
|
87
92
|
child.redis_pool = redis_pool
|
88
|
-
child.sessions = sessions
|
89
93
|
end
|
90
94
|
|
91
95
|
def settings
|
92
96
|
self.class.settings
|
93
97
|
end
|
94
98
|
|
95
|
-
def
|
96
|
-
middlewares
|
99
|
+
def middlewares
|
100
|
+
@middlewares ||= self.class.middlewares
|
97
101
|
end
|
98
102
|
|
99
|
-
def
|
100
|
-
|
103
|
+
def use(*args, &block)
|
104
|
+
middlewares << [args, block]
|
101
105
|
end
|
102
106
|
|
103
107
|
def call(env)
|
@@ -125,18 +129,8 @@ module Sidekiq
|
|
125
129
|
send(:"#{attribute}=", value)
|
126
130
|
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
attr_writer :sessions
|
132
|
-
|
133
|
-
def sessions
|
134
|
-
unless instance_variable_defined?("@sessions")
|
135
|
-
@sessions = self.class.sessions
|
136
|
-
@sessions = @sessions.to_hash.dup if @sessions.respond_to?(:to_hash)
|
137
|
-
end
|
138
|
-
|
139
|
-
@sessions
|
132
|
+
def sessions=(val)
|
133
|
+
puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
|
140
134
|
end
|
141
135
|
|
142
136
|
def self.register(extension)
|
@@ -145,50 +139,19 @@ module Sidekiq
|
|
145
139
|
|
146
140
|
private
|
147
141
|
|
148
|
-
def using?(middleware)
|
149
|
-
middlewares.any? do |(m, _)|
|
150
|
-
m.is_a?(Array) && (m[0] == middleware || m[0].is_a?(middleware))
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def build_sessions
|
155
|
-
middlewares = self.middlewares
|
156
|
-
|
157
|
-
unless using?(::Rack::Protection) || ENV["RACK_ENV"] == "test"
|
158
|
-
middlewares.unshift [[::Rack::Protection, {use: :authenticity_token}], nil]
|
159
|
-
end
|
160
|
-
|
161
|
-
s = sessions
|
162
|
-
return unless s
|
163
|
-
|
164
|
-
unless using? ::Rack::Session::Cookie
|
165
|
-
unless (secret = Web.session_secret)
|
166
|
-
require "securerandom"
|
167
|
-
secret = SecureRandom.hex(64)
|
168
|
-
end
|
169
|
-
|
170
|
-
options = {secret: secret}
|
171
|
-
options = options.merge(s.to_hash) if s.respond_to? :to_hash
|
172
|
-
|
173
|
-
middlewares.unshift [[::Rack::Session::Cookie, options], nil]
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
142
|
def build
|
178
|
-
build_sessions
|
179
|
-
|
180
|
-
middlewares = self.middlewares
|
181
143
|
klass = self.class
|
144
|
+
m = middlewares
|
182
145
|
|
183
146
|
::Rack::Builder.new do
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
147
|
+
use Rack::Static, :urls => ["/stylesheets", "/images", "/javascripts"],
|
148
|
+
:root => ASSETS,
|
149
|
+
:cascade => true,
|
150
|
+
:header_rules => [
|
151
|
+
[:all, {'Cache-Control' => 'public, max-age=86400'}],
|
152
|
+
]
|
153
|
+
m.each { |middleware, block| use(*middleware, &block) }
|
154
|
+
use Sidekiq::Web::CsrfProtection unless $TESTING
|
192
155
|
run WebApplication.new(klass)
|
193
156
|
end
|
194
157
|
end
|