sidekiq 6.4.2 → 6.5.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 +4 -4
- data/Changes.md +35 -0
- data/bin/sidekiqload +15 -3
- data/lib/sidekiq/api.rb +160 -32
- data/lib/sidekiq/cli.rb +34 -32
- data/lib/sidekiq/client.rb +4 -4
- data/lib/sidekiq/component.rb +65 -0
- data/lib/sidekiq/delay.rb +1 -1
- data/lib/sidekiq/fetch.rb +16 -14
- data/lib/sidekiq/job_retry.rb +50 -34
- data/lib/sidekiq/job_util.rb +7 -3
- data/lib/sidekiq/launcher.rb +22 -19
- data/lib/sidekiq/logger.rb +1 -1
- data/lib/sidekiq/manager.rb +23 -20
- data/lib/sidekiq/metrics/deploy.rb +47 -0
- data/lib/sidekiq/metrics/query.rb +124 -0
- data/lib/sidekiq/metrics/shared.rb +94 -0
- data/lib/sidekiq/metrics/tracking.rb +134 -0
- data/lib/sidekiq/middleware/chain.rb +82 -38
- data/lib/sidekiq/middleware/current_attributes.rb +10 -4
- data/lib/sidekiq/middleware/i18n.rb +2 -0
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/paginator.rb +2 -2
- data/lib/sidekiq/processor.rb +13 -13
- data/lib/sidekiq/rails.rb +5 -5
- data/lib/sidekiq/redis_client_adapter.rb +154 -0
- data/lib/sidekiq/redis_connection.rb +80 -47
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +11 -10
- data/lib/sidekiq/testing.rb +1 -1
- data/lib/sidekiq/transaction_aware_client.rb +45 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +13 -0
- data/lib/sidekiq/web/helpers.rb +25 -2
- data/lib/sidekiq/web.rb +4 -0
- data/lib/sidekiq/worker.rb +2 -1
- data/lib/sidekiq.rb +87 -18
- data/sidekiq.gemspec +1 -1
- data/web/assets/javascripts/application.js +1 -1
- data/web/assets/javascripts/dashboard.js +0 -17
- data/web/assets/javascripts/graph.js +16 -0
- data/web/locales/en.yml +4 -0
- data/web/locales/pt-br.yml +27 -9
- data/web/views/_nav.erb +1 -1
- data/web/views/busy.erb +1 -1
- data/web/views/dashboard.erb +1 -0
- data/web/views/metrics.erb +59 -0
- data/web/views/metrics_for_job.erb +92 -0
- data/web/views/queue.erb +5 -1
- metadata +16 -6
- data/lib/sidekiq/exception_handler.rb +0 -27
- data/lib/sidekiq/util.rb +0 -108
@@ -1,82 +1,102 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "sidekiq/middleware/modules"
|
4
|
+
|
3
5
|
module Sidekiq
|
4
6
|
# Middleware is code configured to run before/after
|
5
|
-
# a
|
7
|
+
# a job is processed. It is patterned after Rack
|
6
8
|
# middleware. Middleware exists for the client side
|
7
9
|
# (pushing jobs onto the queue) as well as the server
|
8
10
|
# side (when jobs are actually processed).
|
9
11
|
#
|
12
|
+
# Callers will register middleware Classes and Sidekiq will
|
13
|
+
# create new instances of the middleware for every job. This
|
14
|
+
# is important so that instance state is not shared accidentally
|
15
|
+
# between job executions.
|
16
|
+
#
|
10
17
|
# To add middleware for the client:
|
11
18
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
19
|
+
# Sidekiq.configure_client do |config|
|
20
|
+
# config.client_middleware do |chain|
|
21
|
+
# chain.add MyClientHook
|
22
|
+
# end
|
15
23
|
# end
|
16
|
-
# end
|
17
24
|
#
|
18
25
|
# To modify middleware for the server, just call
|
19
26
|
# with another block:
|
20
27
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
28
|
+
# Sidekiq.configure_server do |config|
|
29
|
+
# config.server_middleware do |chain|
|
30
|
+
# chain.add MyServerHook
|
31
|
+
# chain.remove ActiveRecord
|
32
|
+
# end
|
25
33
|
# end
|
26
|
-
# end
|
27
34
|
#
|
28
35
|
# To insert immediately preceding another entry:
|
29
36
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
37
|
+
# Sidekiq.configure_client do |config|
|
38
|
+
# config.client_middleware do |chain|
|
39
|
+
# chain.insert_before ActiveRecord, MyClientHook
|
40
|
+
# end
|
33
41
|
# end
|
34
|
-
# end
|
35
42
|
#
|
36
43
|
# To insert immediately after another entry:
|
37
44
|
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
45
|
+
# Sidekiq.configure_client do |config|
|
46
|
+
# config.client_middleware do |chain|
|
47
|
+
# chain.insert_after ActiveRecord, MyClientHook
|
48
|
+
# end
|
41
49
|
# end
|
42
|
-
# end
|
43
50
|
#
|
44
51
|
# This is an example of a minimal server middleware:
|
45
52
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
53
|
+
# class MyServerHook
|
54
|
+
# include Sidekiq::ServerMiddleware
|
55
|
+
#
|
56
|
+
# def call(job_instance, msg, queue)
|
57
|
+
# logger.info "Before job"
|
58
|
+
# redis {|conn| conn.get("foo") } # do something in Redis
|
59
|
+
# yield
|
60
|
+
# logger.info "After job"
|
61
|
+
# end
|
51
62
|
# end
|
52
|
-
# end
|
53
63
|
#
|
54
64
|
# This is an example of a minimal client middleware, note
|
55
65
|
# the method must return the result or the job will not push
|
56
66
|
# to Redis:
|
57
67
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
68
|
+
# class MyClientHook
|
69
|
+
# include Sidekiq::ClientMiddleware
|
70
|
+
#
|
71
|
+
# def call(job_class, msg, queue, redis_pool)
|
72
|
+
# logger.info "Before push"
|
73
|
+
# result = yield
|
74
|
+
# logger.info "After push"
|
75
|
+
# result
|
76
|
+
# end
|
64
77
|
# end
|
65
|
-
# end
|
66
78
|
#
|
67
79
|
module Middleware
|
68
80
|
class Chain
|
69
81
|
include Enumerable
|
70
82
|
|
83
|
+
# A unique instance of the middleware chain is created for
|
84
|
+
# each job executed in order to be thread-safe.
|
85
|
+
# @param copy [Sidekiq::Middleware::Chain] New instance of Chain
|
86
|
+
# @returns nil
|
71
87
|
def initialize_copy(copy)
|
72
88
|
copy.instance_variable_set(:@entries, entries.dup)
|
89
|
+
nil
|
73
90
|
end
|
74
91
|
|
92
|
+
# Iterate through each middleware in the chain
|
75
93
|
def each(&block)
|
76
94
|
entries.each(&block)
|
77
95
|
end
|
78
96
|
|
79
|
-
|
97
|
+
# @api private
|
98
|
+
def initialize(config = nil) # :nodoc:
|
99
|
+
@config = config
|
80
100
|
@entries = nil
|
81
101
|
yield self if block_given?
|
82
102
|
end
|
@@ -85,38 +105,55 @@ module Sidekiq
|
|
85
105
|
@entries ||= []
|
86
106
|
end
|
87
107
|
|
108
|
+
# Remove all middleware matching the given Class
|
109
|
+
# @param klass [Class]
|
88
110
|
def remove(klass)
|
89
111
|
entries.delete_if { |entry| entry.klass == klass }
|
90
112
|
end
|
91
113
|
|
114
|
+
# Add the given middleware to the end of the chain.
|
115
|
+
# Sidekiq will call `klass.new(*args)` to create a clean
|
116
|
+
# copy of your middleware for every job executed.
|
117
|
+
#
|
118
|
+
# chain.add(Statsd::Metrics, { collector: "localhost:8125" })
|
119
|
+
#
|
120
|
+
# @param klass [Class] Your middleware class
|
121
|
+
# @param *args [Array<Object>] Set of arguments to pass to every instance of your middleware
|
92
122
|
def add(klass, *args)
|
93
123
|
remove(klass)
|
94
|
-
entries << Entry.new(klass, *args)
|
124
|
+
entries << Entry.new(@config, klass, *args)
|
95
125
|
end
|
96
126
|
|
127
|
+
# Identical to {#add} except the middleware is added to the front of the chain.
|
97
128
|
def prepend(klass, *args)
|
98
129
|
remove(klass)
|
99
|
-
entries.insert(0, Entry.new(klass, *args))
|
130
|
+
entries.insert(0, Entry.new(@config, klass, *args))
|
100
131
|
end
|
101
132
|
|
133
|
+
# Inserts +newklass+ before +oldklass+ in the chain.
|
134
|
+
# Useful if one middleware must run before another middleware.
|
102
135
|
def insert_before(oldklass, newklass, *args)
|
103
136
|
i = entries.index { |entry| entry.klass == newklass }
|
104
|
-
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
137
|
+
new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
|
105
138
|
i = entries.index { |entry| entry.klass == oldklass } || 0
|
106
139
|
entries.insert(i, new_entry)
|
107
140
|
end
|
108
141
|
|
142
|
+
# Inserts +newklass+ after +oldklass+ in the chain.
|
143
|
+
# Useful if one middleware must run after another middleware.
|
109
144
|
def insert_after(oldklass, newklass, *args)
|
110
145
|
i = entries.index { |entry| entry.klass == newklass }
|
111
|
-
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
146
|
+
new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
|
112
147
|
i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
|
113
148
|
entries.insert(i + 1, new_entry)
|
114
149
|
end
|
115
150
|
|
151
|
+
# @return [Boolean] if the given class is already in the chain
|
116
152
|
def exists?(klass)
|
117
153
|
any? { |entry| entry.klass == klass }
|
118
154
|
end
|
119
155
|
|
156
|
+
# @return [Boolean] if the chain contains no middleware
|
120
157
|
def empty?
|
121
158
|
@entries.nil? || @entries.empty?
|
122
159
|
end
|
@@ -129,6 +166,8 @@ module Sidekiq
|
|
129
166
|
entries.clear
|
130
167
|
end
|
131
168
|
|
169
|
+
# Used by Sidekiq to execute the middleware at runtime
|
170
|
+
# @api private
|
132
171
|
def invoke(*args)
|
133
172
|
return yield if empty?
|
134
173
|
|
@@ -146,16 +185,21 @@ module Sidekiq
|
|
146
185
|
|
147
186
|
private
|
148
187
|
|
188
|
+
# Represents each link in the middleware chain
|
189
|
+
# @api private
|
149
190
|
class Entry
|
150
191
|
attr_reader :klass
|
151
192
|
|
152
|
-
def initialize(klass, *args)
|
193
|
+
def initialize(config, klass, *args)
|
194
|
+
@config = config
|
153
195
|
@klass = klass
|
154
196
|
@args = args
|
155
197
|
end
|
156
198
|
|
157
199
|
def make_new
|
158
|
-
@klass.new(*@args)
|
200
|
+
x = @klass.new(*@args)
|
201
|
+
x.config = @config if @config && x.respond_to?(:config=)
|
202
|
+
x
|
159
203
|
end
|
160
204
|
end
|
161
205
|
end
|
@@ -15,22 +15,28 @@ module Sidekiq
|
|
15
15
|
#
|
16
16
|
module CurrentAttributes
|
17
17
|
class Save
|
18
|
+
include Sidekiq::ClientMiddleware
|
19
|
+
|
18
20
|
def initialize(cattr)
|
19
21
|
@klass = cattr
|
20
22
|
end
|
21
23
|
|
22
24
|
def call(_, job, _, _)
|
23
25
|
attrs = @klass.attributes
|
24
|
-
if
|
25
|
-
job
|
26
|
-
|
27
|
-
|
26
|
+
if attrs.any?
|
27
|
+
if job.has_key?("cattr")
|
28
|
+
job["cattr"].merge!(attrs)
|
29
|
+
else
|
30
|
+
job["cattr"] = attrs
|
31
|
+
end
|
28
32
|
end
|
29
33
|
yield
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
37
|
class Load
|
38
|
+
include Sidekiq::ServerMiddleware
|
39
|
+
|
34
40
|
def initialize(cattr)
|
35
41
|
@klass = cattr
|
36
42
|
end
|
@@ -10,6 +10,7 @@ module Sidekiq::Middleware::I18n
|
|
10
10
|
# Get the current locale and store it in the message
|
11
11
|
# to be sent to Sidekiq.
|
12
12
|
class Client
|
13
|
+
include Sidekiq::ClientMiddleware
|
13
14
|
def call(_jobclass, job, _queue, _redis)
|
14
15
|
job["locale"] ||= I18n.locale
|
15
16
|
yield
|
@@ -18,6 +19,7 @@ module Sidekiq::Middleware::I18n
|
|
18
19
|
|
19
20
|
# Pull the msg locale out and set the current thread to use it.
|
20
21
|
class Server
|
22
|
+
include Sidekiq::ServerMiddleware
|
21
23
|
def call(_jobclass, job, _queue, &block)
|
22
24
|
I18n.with_locale(job.fetch("locale", I18n.default_locale), &block)
|
23
25
|
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
|
data/lib/sidekiq/paginator.rb
CHANGED
@@ -19,9 +19,9 @@ module Sidekiq
|
|
19
19
|
total_size, items = conn.multi { |transaction|
|
20
20
|
transaction.zcard(key)
|
21
21
|
if rev
|
22
|
-
transaction.zrevrange(key, starting, ending,
|
22
|
+
transaction.zrevrange(key, starting, ending, withscores: true)
|
23
23
|
else
|
24
|
-
transaction.zrange(key, starting, ending,
|
24
|
+
transaction.zrange(key, starting, ending, withscores: true)
|
25
25
|
end
|
26
26
|
}
|
27
27
|
[current_page, total_size, items]
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "sidekiq/util"
|
4
3
|
require "sidekiq/fetch"
|
5
4
|
require "sidekiq/job_logger"
|
6
5
|
require "sidekiq/job_retry"
|
@@ -15,29 +14,30 @@ module Sidekiq
|
|
15
14
|
# b. run the middleware chain
|
16
15
|
# c. call #perform
|
17
16
|
#
|
18
|
-
# A Processor can exit due to shutdown
|
19
|
-
#
|
17
|
+
# A Processor can exit due to shutdown or due to
|
18
|
+
# an error during job execution.
|
20
19
|
#
|
21
20
|
# If an error occurs in the job execution, the
|
22
21
|
# Processor calls the Manager to create a new one
|
23
22
|
# to replace itself and exits.
|
24
23
|
#
|
25
24
|
class Processor
|
26
|
-
include
|
25
|
+
include Sidekiq::Component
|
27
26
|
|
28
27
|
attr_reader :thread
|
29
28
|
attr_reader :job
|
30
29
|
|
31
|
-
def initialize(
|
32
|
-
@
|
30
|
+
def initialize(options, &block)
|
31
|
+
@callback = block
|
33
32
|
@down = false
|
34
33
|
@done = false
|
35
34
|
@job = nil
|
36
35
|
@thread = nil
|
36
|
+
@config = options
|
37
37
|
@strategy = options[:fetch]
|
38
38
|
@reloader = options[:reloader] || proc { |&block| block.call }
|
39
39
|
@job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
|
40
|
-
@retrier = Sidekiq::JobRetry.new
|
40
|
+
@retrier = Sidekiq::JobRetry.new(options)
|
41
41
|
end
|
42
42
|
|
43
43
|
def terminate(wait = false)
|
@@ -66,14 +66,14 @@ module Sidekiq
|
|
66
66
|
|
67
67
|
def run
|
68
68
|
process_one until @done
|
69
|
-
@
|
69
|
+
@callback.call(self)
|
70
70
|
rescue Sidekiq::Shutdown
|
71
|
-
@
|
71
|
+
@callback.call(self)
|
72
72
|
rescue Exception => ex
|
73
|
-
@
|
73
|
+
@callback.call(self, ex)
|
74
74
|
end
|
75
75
|
|
76
|
-
def process_one
|
76
|
+
def process_one(&block)
|
77
77
|
@job = fetch
|
78
78
|
process(@job) if @job
|
79
79
|
@job = nil
|
@@ -160,7 +160,7 @@ module Sidekiq
|
|
160
160
|
ack = false
|
161
161
|
begin
|
162
162
|
dispatch(job_hash, queue, jobstr) do |inst|
|
163
|
-
|
163
|
+
@config.server_middleware.invoke(inst, job_hash, queue) do
|
164
164
|
execute_job(inst, job_hash["args"])
|
165
165
|
end
|
166
166
|
end
|
@@ -174,7 +174,7 @@ module Sidekiq
|
|
174
174
|
# signals that we created a retry successfully. We can acknowlege the job.
|
175
175
|
ack = true
|
176
176
|
e = h.cause || h
|
177
|
-
handle_exception(e, {context: "Job raised exception", job: job_hash
|
177
|
+
handle_exception(e, {context: "Job raised exception", job: job_hash})
|
178
178
|
raise e
|
179
179
|
rescue Exception => ex
|
180
180
|
# Unexpected error! This is very bad and indicates an exception that got past
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -38,12 +38,12 @@ module Sidekiq
|
|
38
38
|
end
|
39
39
|
|
40
40
|
initializer "sidekiq.rails_logger" do
|
41
|
-
Sidekiq.configure_server do |
|
41
|
+
Sidekiq.configure_server do |config|
|
42
42
|
# This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
|
43
43
|
# it will appear in the Sidekiq console with all of the job context. See #5021 and
|
44
44
|
# https://github.com/rails/rails/blob/b5f2b550f69a99336482739000c58e4e04e033aa/railties/lib/rails/commands/server/server_command.rb#L82-L84
|
45
|
-
unless ::Rails.logger ==
|
46
|
-
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(
|
45
|
+
unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
46
|
+
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -60,8 +60,8 @@ module Sidekiq
|
|
60
60
|
#
|
61
61
|
# None of this matters on the client-side, only within the Sidekiq process itself.
|
62
62
|
config.after_initialize do
|
63
|
-
Sidekiq.configure_server do |
|
64
|
-
|
63
|
+
Sidekiq.configure_server do |config|
|
64
|
+
config[:reloader] = Sidekiq::Rails::Reloader.new
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "connection_pool"
|
4
|
+
require "redis_client"
|
5
|
+
require "redis_client/decorator"
|
6
|
+
require "uri"
|
7
|
+
|
8
|
+
module Sidekiq
|
9
|
+
class RedisClientAdapter
|
10
|
+
BaseError = RedisClient::Error
|
11
|
+
CommandError = RedisClient::CommandError
|
12
|
+
|
13
|
+
module CompatMethods
|
14
|
+
def info
|
15
|
+
@client.call("INFO") { |i| i.lines(chomp: true).map { |l| l.split(":", 2) }.select { |l| l.size == 2 }.to_h }
|
16
|
+
end
|
17
|
+
|
18
|
+
def evalsha(sha, keys, argv)
|
19
|
+
@client.call("EVALSHA", sha, keys.size, *keys, *argv)
|
20
|
+
end
|
21
|
+
|
22
|
+
def brpoplpush(*args)
|
23
|
+
@client.blocking_call(false, "BRPOPLPUSH", *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def brpop(*args)
|
27
|
+
@client.blocking_call(false, "BRPOP", *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def set(*args)
|
31
|
+
@client.call("SET", *args) { |r| r == "OK" }
|
32
|
+
end
|
33
|
+
ruby2_keywords :set if respond_to?(:ruby2_keywords, true)
|
34
|
+
|
35
|
+
def sismember(*args)
|
36
|
+
@client.call("SISMEMBER", *args) { |c| c > 0 }
|
37
|
+
end
|
38
|
+
|
39
|
+
def exists?(key)
|
40
|
+
@client.call("EXISTS", key) { |c| c > 0 }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def method_missing(*args, &block)
|
46
|
+
@client.call(*args, *block)
|
47
|
+
end
|
48
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
49
|
+
|
50
|
+
def respond_to_missing?(name, include_private = false)
|
51
|
+
super # Appease the linter. We can't tell what is a valid command.
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
CompatClient = RedisClient::Decorator.create(CompatMethods)
|
56
|
+
|
57
|
+
class CompatClient
|
58
|
+
%i[scan sscan zscan hscan].each do |method|
|
59
|
+
alias_method :"#{method}_each", method
|
60
|
+
undef_method method
|
61
|
+
end
|
62
|
+
|
63
|
+
def disconnect!
|
64
|
+
@client.close
|
65
|
+
end
|
66
|
+
|
67
|
+
def connection
|
68
|
+
{id: @client.id}
|
69
|
+
end
|
70
|
+
|
71
|
+
def redis
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def _client
|
76
|
+
@client
|
77
|
+
end
|
78
|
+
|
79
|
+
def message
|
80
|
+
yield nil, @queue.pop
|
81
|
+
end
|
82
|
+
|
83
|
+
# NB: this method does not return
|
84
|
+
def subscribe(chan)
|
85
|
+
@queue = ::Queue.new
|
86
|
+
|
87
|
+
pubsub = @client.pubsub
|
88
|
+
pubsub.call("subscribe", chan)
|
89
|
+
|
90
|
+
loop do
|
91
|
+
evt = pubsub.next_event
|
92
|
+
next if evt.nil?
|
93
|
+
next unless evt[0] == "message" && evt[1] == chan
|
94
|
+
|
95
|
+
(_, _, msg) = evt
|
96
|
+
@queue << msg
|
97
|
+
yield self
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(options)
|
103
|
+
opts = client_opts(options)
|
104
|
+
@config = if opts.key?(:sentinels)
|
105
|
+
RedisClient.sentinel(**opts)
|
106
|
+
else
|
107
|
+
RedisClient.config(**opts)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def new_client
|
112
|
+
CompatClient.new(@config.new_client)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def client_opts(options)
|
118
|
+
opts = options.dup
|
119
|
+
|
120
|
+
if opts[:namespace]
|
121
|
+
Sidekiq.logger.error("Your Redis configuration uses the namespace '#{opts[:namespace]}' but this feature isn't supported by redis-client. " \
|
122
|
+
"Either use the redis adapter or remove the namespace.")
|
123
|
+
Kernel.exit(-127)
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.delete(:size)
|
127
|
+
opts.delete(:pool_timeout)
|
128
|
+
|
129
|
+
if opts[:network_timeout]
|
130
|
+
opts[:timeout] = opts[:network_timeout]
|
131
|
+
opts.delete(:network_timeout)
|
132
|
+
end
|
133
|
+
|
134
|
+
if opts[:driver]
|
135
|
+
opts[:driver] = opts[:driver].to_sym
|
136
|
+
end
|
137
|
+
|
138
|
+
opts[:name] = opts.delete(:master_name) if opts.key?(:master_name)
|
139
|
+
opts[:role] = opts[:role].to_sym if opts.key?(:role)
|
140
|
+
opts.delete(:url) if opts.key?(:sentinels)
|
141
|
+
|
142
|
+
# Issue #3303, redis-rb will silently retry an operation.
|
143
|
+
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
|
144
|
+
# is performed twice but I believe this is much, much rarer
|
145
|
+
# than the reconnect silently fixing a problem; we keep it
|
146
|
+
# on by default.
|
147
|
+
opts[:reconnect_attempts] ||= 1
|
148
|
+
|
149
|
+
opts
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
Sidekiq::RedisConnection.adapter = Sidekiq::RedisClientAdapter
|