sidekiq 5.0.1 → 5.2.9
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/.circleci/config.yml +61 -0
- data/.github/issue_template.md +3 -1
- data/.gitignore +2 -0
- data/.travis.yml +6 -13
- data/COMM-LICENSE +11 -9
- data/Changes.md +136 -1
- data/Ent-Changes.md +46 -3
- data/Gemfile +14 -20
- data/LICENSE +1 -1
- data/Pro-4.0-Upgrade.md +35 -0
- data/Pro-Changes.md +125 -0
- data/README.md +5 -3
- data/Rakefile +2 -5
- data/bin/sidekiqctl +13 -92
- data/bin/sidekiqload +2 -2
- data/lib/sidekiq.rb +24 -15
- data/lib/sidekiq/api.rb +83 -37
- data/lib/sidekiq/cli.rb +106 -76
- data/lib/sidekiq/client.rb +36 -33
- data/lib/sidekiq/ctl.rb +221 -0
- data/lib/sidekiq/delay.rb +23 -2
- data/lib/sidekiq/exception_handler.rb +2 -4
- data/lib/sidekiq/fetch.rb +1 -1
- data/lib/sidekiq/job_logger.rb +4 -3
- data/lib/sidekiq/job_retry.rb +51 -24
- data/lib/sidekiq/launcher.rb +18 -12
- data/lib/sidekiq/logging.rb +9 -5
- data/lib/sidekiq/manager.rb +5 -6
- data/lib/sidekiq/middleware/server/active_record.rb +2 -1
- data/lib/sidekiq/processor.rb +85 -48
- data/lib/sidekiq/rails.rb +7 -0
- data/lib/sidekiq/redis_connection.rb +40 -4
- data/lib/sidekiq/scheduled.rb +35 -8
- data/lib/sidekiq/testing.rb +4 -4
- data/lib/sidekiq/util.rb +5 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +4 -4
- data/lib/sidekiq/web/action.rb +2 -2
- data/lib/sidekiq/web/application.rb +24 -2
- data/lib/sidekiq/web/helpers.rb +18 -8
- data/lib/sidekiq/web/router.rb +10 -10
- data/lib/sidekiq/worker.rb +39 -22
- data/sidekiq.gemspec +6 -17
- data/web/assets/javascripts/application.js +0 -0
- data/web/assets/javascripts/dashboard.js +15 -5
- data/web/assets/stylesheets/application.css +35 -2
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +1 -0
- data/web/locales/en.yml +2 -0
- data/web/locales/es.yml +4 -3
- data/web/locales/ja.yml +5 -3
- data/web/views/_footer.erb +3 -0
- data/web/views/_nav.erb +3 -17
- data/web/views/layout.erb +1 -1
- data/web/views/queue.erb +1 -0
- data/web/views/queues.erb +2 -0
- data/web/views/retries.erb +4 -0
- metadata +20 -156
data/lib/sidekiq/launcher.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
require 'sidekiq/manager'
|
4
3
|
require 'sidekiq/fetch'
|
@@ -14,6 +13,8 @@ module Sidekiq
|
|
14
13
|
|
15
14
|
attr_accessor :manager, :poller, :fetcher
|
16
15
|
|
16
|
+
STATS_TTL = 5*365*24*60*60
|
17
|
+
|
17
18
|
def initialize(options)
|
18
19
|
@manager = Sidekiq::Manager.new(options)
|
19
20
|
@poller = Sidekiq::Scheduled::Poller.new
|
@@ -39,7 +40,7 @@ module Sidekiq
|
|
39
40
|
# return until all work is complete and cleaned up.
|
40
41
|
# It can take up to the timeout to complete.
|
41
42
|
def stop
|
42
|
-
deadline =
|
43
|
+
deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @options[:timeout]
|
43
44
|
|
44
45
|
@done = true
|
45
46
|
@manager.quiet
|
@@ -73,19 +74,24 @@ module Sidekiq
|
|
73
74
|
key = identity
|
74
75
|
fails = procd = 0
|
75
76
|
begin
|
76
|
-
Processor::FAILURE.
|
77
|
-
Processor::PROCESSED.
|
77
|
+
fails = Processor::FAILURE.reset
|
78
|
+
procd = Processor::PROCESSED.reset
|
79
|
+
curstate = Processor::WORKER_STATE.dup
|
78
80
|
|
79
|
-
workers_key = "#{key}:workers"
|
80
|
-
nowdate = Time.now.utc.strftime("%Y-%m-%d"
|
81
|
+
workers_key = "#{key}:workers"
|
82
|
+
nowdate = Time.now.utc.strftime("%Y-%m-%d")
|
81
83
|
Sidekiq.redis do |conn|
|
82
84
|
conn.multi do
|
83
|
-
conn.incrby("stat:processed"
|
85
|
+
conn.incrby("stat:processed", procd)
|
84
86
|
conn.incrby("stat:processed:#{nowdate}", procd)
|
85
|
-
conn.
|
87
|
+
conn.expire("stat:processed:#{nowdate}", STATS_TTL)
|
88
|
+
|
89
|
+
conn.incrby("stat:failed", fails)
|
86
90
|
conn.incrby("stat:failed:#{nowdate}", fails)
|
91
|
+
conn.expire("stat:failed:#{nowdate}", STATS_TTL)
|
92
|
+
|
87
93
|
conn.del(workers_key)
|
88
|
-
|
94
|
+
curstate.each_pair do |tid, hash|
|
89
95
|
conn.hset(workers_key, tid, Sidekiq.dump_json(hash))
|
90
96
|
end
|
91
97
|
conn.expire(workers_key, 60)
|
@@ -97,7 +103,7 @@ module Sidekiq
|
|
97
103
|
conn.multi do
|
98
104
|
conn.sadd('processes', key)
|
99
105
|
conn.exists(key)
|
100
|
-
conn.hmset(key, 'info', to_json, 'busy',
|
106
|
+
conn.hmset(key, 'info', to_json, 'busy', curstate.size, 'beat', Time.now.to_f, 'quiet', @done)
|
101
107
|
conn.expire(key, 60)
|
102
108
|
conn.rpop("#{key}-signals")
|
103
109
|
end
|
@@ -113,8 +119,8 @@ module Sidekiq
|
|
113
119
|
# ignore all redis/network issues
|
114
120
|
logger.error("heartbeat: #{e.message}")
|
115
121
|
# don't lose the counts if there was a network issue
|
116
|
-
Processor::PROCESSED.
|
117
|
-
Processor::FAILURE.
|
122
|
+
Processor::PROCESSED.incr(procd)
|
123
|
+
Processor::FAILURE.incr(fails)
|
118
124
|
end
|
119
125
|
end
|
120
126
|
|
data/lib/sidekiq/logging.rb
CHANGED
@@ -11,7 +11,7 @@ module Sidekiq
|
|
11
11
|
|
12
12
|
# Provide a call() method that returns the formatted message.
|
13
13
|
def call(severity, time, program_name, message)
|
14
|
-
"#{time.utc.iso8601(3)} #{::Process.pid} TID-#{
|
14
|
+
"#{time.utc.iso8601(3)} #{::Process.pid} TID-#{Sidekiq::Logging.tid}#{context} #{severity}: #{message}\n"
|
15
15
|
end
|
16
16
|
|
17
17
|
def context
|
@@ -22,16 +22,20 @@ module Sidekiq
|
|
22
22
|
|
23
23
|
class WithoutTimestamp < Pretty
|
24
24
|
def call(severity, time, program_name, message)
|
25
|
-
"#{::Process.pid} TID-#{
|
25
|
+
"#{::Process.pid} TID-#{Sidekiq::Logging.tid}#{context} #{severity}: #{message}\n"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def self.tid
|
30
|
+
Thread.current['sidekiq_tid'] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
31
|
+
end
|
32
|
+
|
29
33
|
def self.job_hash_context(job_hash)
|
30
34
|
# If we're using a wrapper class, like ActiveJob, use the "wrapped"
|
31
35
|
# attribute to expose the underlying thing.
|
32
|
-
klass = job_hash['wrapped'
|
33
|
-
bid = job_hash['bid'
|
34
|
-
"#{klass} JID-#{job_hash['jid'
|
36
|
+
klass = job_hash['wrapped'] || job_hash["class"]
|
37
|
+
bid = job_hash['bid']
|
38
|
+
"#{klass} JID-#{job_hash['jid']}#{" BID-#{bid}" if bid}"
|
35
39
|
end
|
36
40
|
|
37
41
|
def self.with_job_hash_context(job_hash, &block)
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
require 'sidekiq/util'
|
4
3
|
require 'sidekiq/processor'
|
@@ -31,7 +30,7 @@ module Sidekiq
|
|
31
30
|
def initialize(options={})
|
32
31
|
logger.debug { options.inspect }
|
33
32
|
@options = options
|
34
|
-
@count = options[:concurrency] ||
|
33
|
+
@count = options[:concurrency] || 10
|
35
34
|
raise ArgumentError, "Concurrency of #{@count} is not supported" if @count < 1
|
36
35
|
|
37
36
|
@done = false
|
@@ -54,7 +53,7 @@ module Sidekiq
|
|
54
53
|
|
55
54
|
logger.info { "Terminating quiet workers" }
|
56
55
|
@workers.each { |x| x.terminate }
|
57
|
-
fire_event(:quiet, true)
|
56
|
+
fire_event(:quiet, reverse: true)
|
58
57
|
end
|
59
58
|
|
60
59
|
# hack for quicker development / testing environment #2774
|
@@ -62,7 +61,7 @@ module Sidekiq
|
|
62
61
|
|
63
62
|
def stop(deadline)
|
64
63
|
quiet
|
65
|
-
fire_event(:shutdown, true)
|
64
|
+
fire_event(:shutdown, reverse: true)
|
66
65
|
|
67
66
|
# some of the shutdown events can be async,
|
68
67
|
# we don't have any way to know when they're done but
|
@@ -71,11 +70,11 @@ module Sidekiq
|
|
71
70
|
return if @workers.empty?
|
72
71
|
|
73
72
|
logger.info { "Pausing to allow workers to finish..." }
|
74
|
-
remaining = deadline -
|
73
|
+
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
75
74
|
while remaining > PAUSE_TIME
|
76
75
|
return if @workers.empty?
|
77
76
|
sleep PAUSE_TIME
|
78
|
-
remaining = deadline -
|
77
|
+
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
79
78
|
end
|
80
79
|
return if @workers.empty?
|
81
80
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sidekiq
|
2
3
|
module Middleware
|
3
4
|
module Server
|
@@ -6,7 +7,7 @@ module Sidekiq
|
|
6
7
|
def initialize
|
7
8
|
# With Rails 5+ we must use the Reloader **always**.
|
8
9
|
# The reloader handles code loading and db connection management.
|
9
|
-
if ::Rails::VERSION::MAJOR >= 5
|
10
|
+
if defined?(::Rails) && defined?(::Rails::VERSION) && ::Rails::VERSION::MAJOR >= 5
|
10
11
|
raise ArgumentError, "Rails 5 no longer needs or uses the ActiveRecord middleware."
|
11
12
|
end
|
12
13
|
end
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -4,8 +4,6 @@ require 'sidekiq/fetch'
|
|
4
4
|
require 'sidekiq/job_logger'
|
5
5
|
require 'sidekiq/job_retry'
|
6
6
|
require 'thread'
|
7
|
-
require 'concurrent/map'
|
8
|
-
require 'concurrent/atomic/atomic_fixnum'
|
9
7
|
|
10
8
|
module Sidekiq
|
11
9
|
##
|
@@ -39,7 +37,7 @@ module Sidekiq
|
|
39
37
|
@thread = nil
|
40
38
|
@strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
|
41
39
|
@reloader = Sidekiq.options[:reloader]
|
42
|
-
@logging = Sidekiq::JobLogger.new
|
40
|
+
@logging = (mgr.options[:job_logger] || Sidekiq::JobLogger).new
|
43
41
|
@retrier = Sidekiq::JobRetry.new
|
44
42
|
end
|
45
43
|
|
@@ -89,7 +87,7 @@ module Sidekiq
|
|
89
87
|
def get_one
|
90
88
|
begin
|
91
89
|
work = @strategy.retrieve_work
|
92
|
-
(logger.info { "Redis is online, #{
|
90
|
+
(logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }; @down = nil) if @down
|
93
91
|
work
|
94
92
|
rescue Sidekiq::Shutdown
|
95
93
|
rescue => ex
|
@@ -109,11 +107,9 @@ module Sidekiq
|
|
109
107
|
|
110
108
|
def handle_fetch_exception(ex)
|
111
109
|
if !@down
|
112
|
-
@down =
|
110
|
+
@down = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
113
111
|
logger.error("Error fetching job: #{ex}")
|
114
|
-
ex
|
115
|
-
logger.error(bt)
|
116
|
-
end
|
112
|
+
handle_exception(ex)
|
117
113
|
end
|
118
114
|
sleep(1)
|
119
115
|
nil
|
@@ -126,7 +122,7 @@ module Sidekiq
|
|
126
122
|
pristine = cloned(job_hash)
|
127
123
|
|
128
124
|
Sidekiq::Logging.with_job_hash_context(job_hash) do
|
129
|
-
@retrier.global(
|
125
|
+
@retrier.global(pristine, queue) do
|
130
126
|
@logging.call(job_hash, queue) do
|
131
127
|
stats(pristine, queue) do
|
132
128
|
# Rails 5 requires a Reloader to wrap code execution. In order to
|
@@ -134,10 +130,10 @@ module Sidekiq
|
|
134
130
|
# the Reloader. It handles code loading, db connection management, etc.
|
135
131
|
# Effectively this block denotes a "unit of work" to Rails.
|
136
132
|
@reloader.call do
|
137
|
-
klass = constantize(job_hash['class'
|
133
|
+
klass = constantize(job_hash['class'])
|
138
134
|
worker = klass.new
|
139
|
-
worker.jid = job_hash['jid'
|
140
|
-
@retrier.local(worker,
|
135
|
+
worker.jid = job_hash['jid']
|
136
|
+
@retrier.local(worker, pristine, queue) do
|
141
137
|
yield worker
|
142
138
|
end
|
143
139
|
end
|
@@ -151,23 +147,22 @@ module Sidekiq
|
|
151
147
|
jobstr = work.job
|
152
148
|
queue = work.queue_name
|
153
149
|
|
154
|
-
|
150
|
+
# Treat malformed JSON as a special case: job goes straight to the morgue.
|
151
|
+
job_hash = nil
|
155
152
|
begin
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
ack = true
|
164
|
-
raise
|
165
|
-
end
|
153
|
+
job_hash = Sidekiq.load_json(jobstr)
|
154
|
+
rescue => ex
|
155
|
+
handle_exception(ex, { :context => "Invalid JSON for job", :jobstr => jobstr })
|
156
|
+
# we can't notify because the job isn't a valid hash payload.
|
157
|
+
DeadSet.new.kill(jobstr, notify_failure: false)
|
158
|
+
return work.acknowledge
|
159
|
+
end
|
166
160
|
|
167
|
-
|
161
|
+
ack = true
|
162
|
+
begin
|
168
163
|
dispatch(job_hash, queue) do |worker|
|
169
164
|
Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
|
170
|
-
execute_job(worker, cloned(job_hash['args'
|
165
|
+
execute_job(worker, cloned(job_hash['args']))
|
171
166
|
end
|
172
167
|
end
|
173
168
|
rescue Sidekiq::Shutdown
|
@@ -175,50 +170,90 @@ module Sidekiq
|
|
175
170
|
# within the timeout. Don't acknowledge the work since
|
176
171
|
# we didn't properly finish it.
|
177
172
|
ack = false
|
178
|
-
rescue
|
179
|
-
|
173
|
+
rescue Sidekiq::JobRetry::Handled => h
|
174
|
+
# this is the common case: job raised error and Sidekiq::JobRetry::Handled
|
175
|
+
# signals that we created a retry successfully. We can acknowlege the job.
|
176
|
+
e = h.cause ? h.cause : h
|
180
177
|
handle_exception(e, { :context => "Job raised exception", :job => job_hash, :jobstr => jobstr })
|
181
178
|
raise e
|
179
|
+
rescue Exception => ex
|
180
|
+
# Unexpected error! This is very bad and indicates an exception that got past
|
181
|
+
# the retry subsystem (e.g. network partition). We won't acknowledge the job
|
182
|
+
# so it can be rescued when using Sidekiq Pro.
|
183
|
+
ack = false
|
184
|
+
handle_exception(ex, { :context => "Internal exception!", :job => job_hash, :jobstr => jobstr })
|
185
|
+
raise e
|
182
186
|
ensure
|
183
187
|
work.acknowledge if ack
|
184
188
|
end
|
185
189
|
end
|
186
190
|
|
187
|
-
def send_to_morgue(msg)
|
188
|
-
now = Time.now.to_f
|
189
|
-
Sidekiq.redis do |conn|
|
190
|
-
conn.multi do
|
191
|
-
conn.zadd('dead', now, msg)
|
192
|
-
conn.zremrangebyscore('dead', '-inf', now - DeadSet.timeout)
|
193
|
-
conn.zremrangebyrank('dead', 0, -DeadSet.max_jobs)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
191
|
def execute_job(worker, cloned_args)
|
199
192
|
worker.perform(*cloned_args)
|
200
193
|
end
|
201
194
|
|
202
|
-
|
203
|
-
|
195
|
+
# Ruby doesn't provide atomic counters out of the box so we'll
|
196
|
+
# implement something simple ourselves.
|
197
|
+
# https://bugs.ruby-lang.org/issues/14706
|
198
|
+
class Counter
|
199
|
+
def initialize
|
200
|
+
@value = 0
|
201
|
+
@lock = Mutex.new
|
202
|
+
end
|
203
|
+
|
204
|
+
def incr(amount=1)
|
205
|
+
@lock.synchronize { @value = @value + amount }
|
206
|
+
end
|
207
|
+
|
208
|
+
def reset
|
209
|
+
@lock.synchronize { val = @value; @value = 0; val }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# jruby's Hash implementation is not threadsafe, so we wrap it in a mutex here
|
214
|
+
class SharedWorkerState
|
215
|
+
def initialize
|
216
|
+
@worker_state = {}
|
217
|
+
@lock = Mutex.new
|
218
|
+
end
|
219
|
+
|
220
|
+
def set(tid, hash)
|
221
|
+
@lock.synchronize { @worker_state[tid] = hash }
|
222
|
+
end
|
223
|
+
|
224
|
+
def delete(tid)
|
225
|
+
@lock.synchronize { @worker_state.delete(tid) }
|
226
|
+
end
|
227
|
+
|
228
|
+
def dup
|
229
|
+
@lock.synchronize { @worker_state.dup }
|
230
|
+
end
|
231
|
+
|
232
|
+
def size
|
233
|
+
@lock.synchronize { @worker_state.size }
|
234
|
+
end
|
235
|
+
|
236
|
+
def clear
|
237
|
+
@lock.synchronize { @worker_state.clear }
|
238
|
+
end
|
204
239
|
end
|
205
240
|
|
206
|
-
|
207
|
-
|
208
|
-
|
241
|
+
PROCESSED = Counter.new
|
242
|
+
FAILURE = Counter.new
|
243
|
+
WORKER_STATE = SharedWorkerState.new
|
209
244
|
|
210
245
|
def stats(job_hash, queue)
|
211
|
-
tid =
|
212
|
-
WORKER_STATE
|
246
|
+
tid = Sidekiq::Logging.tid
|
247
|
+
WORKER_STATE.set(tid, {:queue => queue, :payload => job_hash, :run_at => Time.now.to_i })
|
213
248
|
|
214
249
|
begin
|
215
250
|
yield
|
216
251
|
rescue Exception
|
217
|
-
FAILURE.
|
252
|
+
FAILURE.incr
|
218
253
|
raise
|
219
254
|
ensure
|
220
255
|
WORKER_STATE.delete(tid)
|
221
|
-
PROCESSED.
|
256
|
+
PROCESSED.incr
|
222
257
|
end
|
223
258
|
end
|
224
259
|
|
@@ -234,7 +269,9 @@ module Sidekiq
|
|
234
269
|
names.shift if names.empty? || names.first.empty?
|
235
270
|
|
236
271
|
names.inject(Object) do |constant, name|
|
237
|
-
|
272
|
+
# the false flag limits search for name to under the constant namespace
|
273
|
+
# which mimics Rails' behaviour
|
274
|
+
constant.const_defined?(name, false) ? constant.const_get(name, false) : constant.const_missing(name)
|
238
275
|
end
|
239
276
|
end
|
240
277
|
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Sidekiq
|
3
4
|
class Rails < ::Rails::Engine
|
4
5
|
# We need to setup this up before any application configuration which might
|
@@ -49,3 +50,9 @@ module Sidekiq
|
|
49
50
|
end
|
50
51
|
end if defined?(::Rails)
|
51
52
|
end
|
53
|
+
|
54
|
+
if defined?(::Rails) && ::Rails::VERSION::MAJOR < 4
|
55
|
+
$stderr.puts("**************************************************")
|
56
|
+
$stderr.puts("⛔️ WARNING: Sidekiq server is no longer supported by Rails 3.2 - please ensure your server/workers are updated")
|
57
|
+
$stderr.puts("**************************************************")
|
58
|
+
end
|
@@ -12,9 +12,18 @@ module Sidekiq
|
|
12
12
|
options[key.to_sym] = options.delete(key)
|
13
13
|
end
|
14
14
|
|
15
|
+
options[:id] = "Sidekiq-#{Sidekiq.server? ? "server" : "client"}-PID-#{$$}" if !options.has_key?(:id)
|
15
16
|
options[:url] ||= determine_redis_provider
|
16
17
|
|
17
|
-
size = options[:size]
|
18
|
+
size = if options[:size]
|
19
|
+
options[:size]
|
20
|
+
elsif Sidekiq.server?
|
21
|
+
Sidekiq.options[:concurrency] + 5
|
22
|
+
elsif ENV['RAILS_MAX_THREADS']
|
23
|
+
Integer(ENV['RAILS_MAX_THREADS'])
|
24
|
+
else
|
25
|
+
5
|
26
|
+
end
|
18
27
|
|
19
28
|
verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
|
20
29
|
|
@@ -37,7 +46,7 @@ module Sidekiq
|
|
37
46
|
# - enterprise's leader election
|
38
47
|
# - enterprise's cron support
|
39
48
|
def verify_sizing(size, concurrency)
|
40
|
-
raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work. Your pool has #{size} connections but
|
49
|
+
raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work. Your pool has #{size} connections but must have at least #{concurrency + 2}" if size <= concurrency
|
41
50
|
end
|
42
51
|
|
43
52
|
def build_client(options)
|
@@ -69,7 +78,7 @@ module Sidekiq
|
|
69
78
|
opts.delete(:network_timeout)
|
70
79
|
end
|
71
80
|
|
72
|
-
opts[:driver] ||= 'ruby'
|
81
|
+
opts[:driver] ||= Redis::Connection.drivers.last || 'ruby'
|
73
82
|
|
74
83
|
# Issue #3303, redis-rb will silently retry an operation.
|
75
84
|
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
|
@@ -100,7 +109,34 @@ module Sidekiq
|
|
100
109
|
end
|
101
110
|
|
102
111
|
def determine_redis_provider
|
103
|
-
|
112
|
+
# If you have this in your environment:
|
113
|
+
# MY_REDIS_URL=redis://hostname.example.com:1238/4
|
114
|
+
# then set:
|
115
|
+
# REDIS_PROVIDER=MY_REDIS_URL
|
116
|
+
# and Sidekiq will find your custom URL variable with no custom
|
117
|
+
# initialization code at all.
|
118
|
+
p = ENV['REDIS_PROVIDER']
|
119
|
+
if p && p =~ /\:/
|
120
|
+
Sidekiq.logger.error <<-EOM
|
121
|
+
|
122
|
+
#################################################################################
|
123
|
+
|
124
|
+
REDIS_PROVIDER should be set to the **name** of the variable which contains the Redis URL, not a URL itself.
|
125
|
+
Platforms like Heroku sell addons that publish a *_URL variable. You tell Sidekiq with REDIS_PROVIDER, e.g.:
|
126
|
+
|
127
|
+
REDIS_PROVIDER=REDISTOGO_URL
|
128
|
+
REDISTOGO_URL=redis://somehost.example.com:6379/4
|
129
|
+
|
130
|
+
Use REDIS_URL if you wish to point Sidekiq to a URL directly.
|
131
|
+
|
132
|
+
This configuration error will crash starting in Sidekiq 5.3.
|
133
|
+
|
134
|
+
#################################################################################
|
135
|
+
EOM
|
136
|
+
end
|
137
|
+
ENV[
|
138
|
+
ENV['REDIS_PROVIDER'] || 'REDIS_URL'
|
139
|
+
]
|
104
140
|
end
|
105
141
|
|
106
142
|
end
|