sidekiq 5.2.3 → 6.0.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 +5 -5
- data/.circleci/config.yml +61 -0
- data/.gitignore +1 -1
- data/.standard.yml +20 -0
- data/6.0-Upgrade.md +70 -0
- data/COMM-LICENSE +11 -9
- data/Changes.md +61 -0
- data/Ent-2.0-Upgrade.md +37 -0
- data/Ent-Changes.md +27 -1
- data/Gemfile +19 -9
- data/Gemfile.lock +196 -0
- data/Pro-5.0-Upgrade.md +25 -0
- data/Pro-Changes.md +19 -2
- data/README.md +17 -31
- data/Rakefile +6 -4
- data/bin/sidekiqload +27 -23
- data/bin/sidekiqmon +9 -0
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
- data/lib/generators/sidekiq/worker_generator.rb +12 -14
- data/lib/sidekiq.rb +56 -43
- data/lib/sidekiq/api.rb +138 -151
- data/lib/sidekiq/cli.rb +141 -206
- data/lib/sidekiq/client.rb +45 -46
- data/lib/sidekiq/delay.rb +5 -6
- data/lib/sidekiq/exception_handler.rb +10 -12
- data/lib/sidekiq/extensions/action_mailer.rb +10 -20
- data/lib/sidekiq/extensions/active_record.rb +9 -7
- data/lib/sidekiq/extensions/class_methods.rb +9 -7
- data/lib/sidekiq/extensions/generic_proxy.rb +4 -4
- data/lib/sidekiq/fetch.rb +5 -6
- data/lib/sidekiq/job_logger.rb +37 -7
- data/lib/sidekiq/job_retry.rb +55 -57
- data/lib/sidekiq/launcher.rb +59 -51
- data/lib/sidekiq/logger.rb +69 -0
- data/lib/sidekiq/manager.rb +7 -9
- data/lib/sidekiq/middleware/chain.rb +3 -2
- data/lib/sidekiq/middleware/i18n.rb +5 -7
- data/lib/sidekiq/monitor.rb +148 -0
- data/lib/sidekiq/paginator.rb +11 -12
- data/lib/sidekiq/processor.rb +68 -58
- data/lib/sidekiq/rails.rb +24 -29
- data/lib/sidekiq/redis_connection.rb +31 -37
- data/lib/sidekiq/scheduled.rb +17 -19
- data/lib/sidekiq/testing.rb +22 -23
- data/lib/sidekiq/testing/inline.rb +2 -1
- data/lib/sidekiq/util.rb +17 -14
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web.rb +41 -49
- data/lib/sidekiq/web/action.rb +14 -10
- data/lib/sidekiq/web/application.rb +61 -58
- data/lib/sidekiq/web/helpers.rb +72 -66
- data/lib/sidekiq/web/router.rb +17 -14
- data/lib/sidekiq/worker.rb +134 -102
- data/sidekiq.gemspec +16 -18
- data/web/assets/javascripts/dashboard.js +2 -21
- data/web/assets/stylesheets/bootstrap.css +1 -1
- data/web/locales/ja.yml +2 -1
- data/web/views/queues.erb +1 -1
- metadata +31 -26
- data/.travis.yml +0 -14
- data/bin/sidekiqctl +0 -237
- data/lib/sidekiq/core_ext.rb +0 -1
- data/lib/sidekiq/logging.rb +0 -122
- data/lib/sidekiq/middleware/server/active_record.rb +0 -23
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
require "set"
|
5
|
+
require "yaml"
|
6
|
+
require "cgi"
|
6
7
|
|
7
8
|
module Sidekiq
|
8
9
|
# This is not a public API
|
9
10
|
module WebHelpers
|
10
11
|
def strings(lang)
|
11
|
-
|
12
|
-
|
12
|
+
@strings ||= {}
|
13
|
+
@strings[lang] ||= begin
|
13
14
|
# Allow sidekiq-web extensions to add locale paths
|
14
15
|
# so extensions can be localized
|
15
16
|
settings.locales.each_with_object({}) do |path, global|
|
@@ -22,19 +23,19 @@ module Sidekiq
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def clear_caches
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
@strings = nil
|
27
|
+
@locale_files = nil
|
28
|
+
@available_locales = nil
|
28
29
|
end
|
29
30
|
|
30
31
|
def locale_files
|
31
|
-
|
32
|
+
@locale_files ||= settings.locales.flat_map { |path|
|
32
33
|
Dir["#{path}/*.yml"]
|
33
|
-
|
34
|
+
}
|
34
35
|
end
|
35
36
|
|
36
37
|
def available_locales
|
37
|
-
|
38
|
+
@available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
|
38
39
|
end
|
39
40
|
|
40
41
|
def find_locale_files(lang)
|
@@ -63,7 +64,7 @@ module Sidekiq
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def poll_path
|
66
|
-
if current_path !=
|
67
|
+
if current_path != "" && params["poll"]
|
67
68
|
root_path + current_path
|
68
69
|
else
|
69
70
|
""
|
@@ -71,24 +72,24 @@ module Sidekiq
|
|
71
72
|
end
|
72
73
|
|
73
74
|
def text_direction
|
74
|
-
get_locale[
|
75
|
+
get_locale["TextDirection"] || "ltr"
|
75
76
|
end
|
76
77
|
|
77
78
|
def rtl?
|
78
|
-
text_direction ==
|
79
|
+
text_direction == "rtl"
|
79
80
|
end
|
80
81
|
|
81
82
|
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
82
83
|
def user_preferred_languages
|
83
|
-
languages = env[
|
84
|
-
languages.to_s.downcase.gsub(/\s+/,
|
85
|
-
locale, quality = language.split(
|
86
|
-
locale
|
84
|
+
languages = env["HTTP_ACCEPT_LANGUAGE"]
|
85
|
+
languages.to_s.downcase.gsub(/\s+/, "").split(",").map { |language|
|
86
|
+
locale, quality = language.split(";q=", 2)
|
87
|
+
locale = nil if locale == "*" # Ignore wildcards
|
87
88
|
quality = quality ? quality.to_f : 1.0
|
88
89
|
[locale, quality]
|
89
|
-
|
90
|
+
}.sort { |(_, left), (_, right)|
|
90
91
|
right <=> left
|
91
|
-
|
92
|
+
}.map(&:first).compact
|
92
93
|
end
|
93
94
|
|
94
95
|
# Given an Accept-Language header like "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2"
|
@@ -97,31 +98,31 @@ module Sidekiq
|
|
97
98
|
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
98
99
|
def locale
|
99
100
|
@locale ||= begin
|
100
|
-
matched_locale = user_preferred_languages.map
|
101
|
-
preferred_language = preferred.split(
|
101
|
+
matched_locale = user_preferred_languages.map { |preferred|
|
102
|
+
preferred_language = preferred.split("-", 2).first
|
102
103
|
|
103
|
-
lang_group = available_locales.select
|
104
|
-
preferred_language == available.split(
|
105
|
-
|
104
|
+
lang_group = available_locales.select { |available|
|
105
|
+
preferred_language == available.split("-", 2).first
|
106
|
+
}
|
106
107
|
|
107
108
|
lang_group.find { |lang| lang == preferred } || lang_group.min_by(&:length)
|
108
|
-
|
109
|
+
}.compact.first
|
109
110
|
|
110
|
-
matched_locale ||
|
111
|
+
matched_locale || "en"
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
114
115
|
# mperham/sidekiq#3243
|
115
116
|
def unfiltered?
|
116
|
-
yield unless env[
|
117
|
+
yield unless env["PATH_INFO"].start_with?("/filter/")
|
117
118
|
end
|
118
119
|
|
119
120
|
def get_locale
|
120
121
|
strings(locale)
|
121
122
|
end
|
122
123
|
|
123
|
-
def t(msg, options={})
|
124
|
-
string = get_locale[msg] || strings(
|
124
|
+
def t(msg, options = {})
|
125
|
+
string = get_locale[msg] || strings("en")[msg] || msg
|
125
126
|
if options.empty?
|
126
127
|
string
|
127
128
|
else
|
@@ -142,9 +143,9 @@ module Sidekiq
|
|
142
143
|
end
|
143
144
|
|
144
145
|
def retries_with_score(score)
|
145
|
-
Sidekiq.redis
|
146
|
-
conn.zrangebyscore(
|
147
|
-
|
146
|
+
Sidekiq.redis { |conn|
|
147
|
+
conn.zrangebyscore("retry", score, score)
|
148
|
+
}.map { |msg| Sidekiq.load_json(msg) }
|
148
149
|
end
|
149
150
|
|
150
151
|
def redis_connection
|
@@ -163,24 +164,24 @@ module Sidekiq
|
|
163
164
|
end
|
164
165
|
|
165
166
|
def root_path
|
166
|
-
"#{env[
|
167
|
+
"#{env["SCRIPT_NAME"]}/"
|
167
168
|
end
|
168
169
|
|
169
170
|
def current_path
|
170
|
-
@current_path ||= request.path_info.gsub(/^\//,
|
171
|
+
@current_path ||= request.path_info.gsub(/^\//, "")
|
171
172
|
end
|
172
173
|
|
173
174
|
def current_status
|
174
|
-
workers.size == 0 ?
|
175
|
+
workers.size == 0 ? "idle" : "active"
|
175
176
|
end
|
176
177
|
|
177
178
|
def relative_time(time)
|
178
179
|
stamp = time.getutc.iso8601
|
179
|
-
%
|
180
|
+
%(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
|
180
181
|
end
|
181
182
|
|
182
183
|
def job_params(job, score)
|
183
|
-
"#{score}-#{job[
|
184
|
+
"#{score}-#{job["jid"]}"
|
184
185
|
end
|
185
186
|
|
186
187
|
def parse_params(params)
|
@@ -188,7 +189,7 @@ module Sidekiq
|
|
188
189
|
[score.to_f, jid]
|
189
190
|
end
|
190
191
|
|
191
|
-
SAFE_QPARAMS = %w
|
192
|
+
SAFE_QPARAMS = %w[page poll]
|
192
193
|
|
193
194
|
# Merge options with current params, filter safe params, and stringify to query string
|
194
195
|
def qparams(options)
|
@@ -197,9 +198,9 @@ module Sidekiq
|
|
197
198
|
options[key.to_s] = options.delete(key)
|
198
199
|
end
|
199
200
|
|
200
|
-
params.merge(options).map
|
201
|
+
params.merge(options).map { |key, value|
|
201
202
|
SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
|
202
|
-
|
203
|
+
}.compact.join("&")
|
203
204
|
end
|
204
205
|
|
205
206
|
def truncate(text, truncate_after_chars = 2000)
|
@@ -207,9 +208,16 @@ module Sidekiq
|
|
207
208
|
end
|
208
209
|
|
209
210
|
def display_args(args, truncate_after_chars = 2000)
|
210
|
-
args
|
211
|
-
|
212
|
-
|
211
|
+
return "Invalid job payload, args is nil" if args.nil?
|
212
|
+
return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
|
213
|
+
|
214
|
+
begin
|
215
|
+
args.map { |arg|
|
216
|
+
h(truncate(to_display(arg), truncate_after_chars))
|
217
|
+
}.join(", ")
|
218
|
+
rescue
|
219
|
+
"Illegal job arguments: #{h args.inspect}"
|
220
|
+
end
|
213
221
|
end
|
214
222
|
|
215
223
|
def csrf_tag
|
@@ -217,23 +225,21 @@ module Sidekiq
|
|
217
225
|
end
|
218
226
|
|
219
227
|
def to_display(arg)
|
228
|
+
arg.inspect
|
229
|
+
rescue
|
220
230
|
begin
|
221
|
-
arg.
|
222
|
-
rescue
|
223
|
-
|
224
|
-
arg.to_s
|
225
|
-
rescue => ex
|
226
|
-
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
227
|
-
end
|
231
|
+
arg.to_s
|
232
|
+
rescue => ex
|
233
|
+
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
228
234
|
end
|
229
235
|
end
|
230
236
|
|
231
|
-
RETRY_JOB_KEYS = Set.new(%w
|
237
|
+
RETRY_JOB_KEYS = Set.new(%w[
|
232
238
|
queue class args retry_count retried_at failed_at
|
233
239
|
jid error_message error_class backtrace
|
234
240
|
error_backtrace enqueued_at retry wrapped
|
235
241
|
created_at
|
236
|
-
)
|
242
|
+
])
|
237
243
|
|
238
244
|
def retry_extra_items(retry_job)
|
239
245
|
@retry_extra_items ||= {}.tap do |extra|
|
@@ -250,8 +256,8 @@ module Sidekiq
|
|
250
256
|
return number
|
251
257
|
end
|
252
258
|
|
253
|
-
options = {delimiter:
|
254
|
-
parts = number.to_s.to_str.split(
|
259
|
+
options = {delimiter: ",", separator: "."}
|
260
|
+
parts = number.to_s.to_str.split(".")
|
255
261
|
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
256
262
|
parts.join(options[:separator])
|
257
263
|
end
|
@@ -259,8 +265,8 @@ module Sidekiq
|
|
259
265
|
def h(text)
|
260
266
|
::Rack::Utils.escape_html(text)
|
261
267
|
rescue ArgumentError => e
|
262
|
-
raise unless e.message.eql?(
|
263
|
-
text.encode!(
|
268
|
+
raise unless e.message.eql?("invalid byte sequence in UTF-8")
|
269
|
+
text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
|
264
270
|
retry
|
265
271
|
end
|
266
272
|
|
@@ -277,7 +283,7 @@ module Sidekiq
|
|
277
283
|
end
|
278
284
|
|
279
285
|
def environment_title_prefix
|
280
|
-
environment = Sidekiq.options[:environment] || ENV[
|
286
|
+
environment = Sidekiq.options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
281
287
|
|
282
288
|
"[#{environment.upcase}] " unless environment == "production"
|
283
289
|
end
|
@@ -287,30 +293,30 @@ module Sidekiq
|
|
287
293
|
end
|
288
294
|
|
289
295
|
def server_utc_time
|
290
|
-
Time.now.utc.strftime(
|
296
|
+
Time.now.utc.strftime("%H:%M:%S UTC")
|
291
297
|
end
|
292
298
|
|
293
299
|
def redis_connection_and_namespace
|
294
300
|
@redis_connection_and_namespace ||= begin
|
295
|
-
namespace_suffix = namespace
|
301
|
+
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
296
302
|
"#{redis_connection}#{namespace_suffix}"
|
297
303
|
end
|
298
304
|
end
|
299
305
|
|
300
306
|
def retry_or_delete_or_kill(job, params)
|
301
|
-
if params[
|
307
|
+
if params["retry"]
|
302
308
|
job.retry
|
303
|
-
elsif params[
|
309
|
+
elsif params["delete"]
|
304
310
|
job.delete
|
305
|
-
elsif params[
|
311
|
+
elsif params["kill"]
|
306
312
|
job.kill
|
307
313
|
end
|
308
314
|
end
|
309
315
|
|
310
316
|
def delete_or_add_queue(job, params)
|
311
|
-
if params[
|
317
|
+
if params["delete"]
|
312
318
|
job.delete
|
313
|
-
elsif params[
|
319
|
+
elsif params["add_to_queue"]
|
314
320
|
job.add_to_queue
|
315
321
|
end
|
316
322
|
end
|
data/lib/sidekiq/web/router.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "rack"
|
3
4
|
|
4
5
|
module Sidekiq
|
5
6
|
module WebRouter
|
6
|
-
GET =
|
7
|
-
DELETE =
|
8
|
-
POST =
|
9
|
-
PUT =
|
10
|
-
PATCH =
|
11
|
-
HEAD =
|
7
|
+
GET = "GET"
|
8
|
+
DELETE = "DELETE"
|
9
|
+
POST = "POST"
|
10
|
+
PUT = "PUT"
|
11
|
+
PATCH = "PATCH"
|
12
|
+
HEAD = "HEAD"
|
12
13
|
|
13
|
-
ROUTE_PARAMS =
|
14
|
-
REQUEST_METHOD =
|
15
|
-
PATH_INFO =
|
14
|
+
ROUTE_PARAMS = "rack.route_params"
|
15
|
+
REQUEST_METHOD = "REQUEST_METHOD"
|
16
|
+
PATH_INFO = "PATH_INFO"
|
16
17
|
|
17
18
|
def get(path, &block)
|
18
19
|
route(GET, path, &block)
|
@@ -35,7 +36,7 @@ module Sidekiq
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def route(method, path, &block)
|
38
|
-
@routes ||= {
|
39
|
+
@routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
|
39
40
|
|
40
41
|
@routes[method] << WebRoute.new(method, path, block)
|
41
42
|
@routes[HEAD] << WebRoute.new(method, path, block) if method == GET
|
@@ -50,7 +51,8 @@ module Sidekiq
|
|
50
51
|
path_info = "/" if path_info == ""
|
51
52
|
|
52
53
|
@routes[request_method].each do |route|
|
53
|
-
|
54
|
+
params = route.match(request_method, path_info)
|
55
|
+
if params
|
54
56
|
env[ROUTE_PARAMS] = params
|
55
57
|
|
56
58
|
return WebAction.new(env, route.block)
|
@@ -77,7 +79,7 @@ module Sidekiq
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def compile
|
80
|
-
if pattern.match(NAMED_SEGMENTS_PATTERN)
|
82
|
+
if pattern.match?(NAMED_SEGMENTS_PATTERN)
|
81
83
|
p = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)')
|
82
84
|
|
83
85
|
Regexp.new("\\A#{p}\\Z")
|
@@ -91,7 +93,8 @@ module Sidekiq
|
|
91
93
|
when String
|
92
94
|
{} if path == matcher
|
93
95
|
else
|
94
|
-
|
96
|
+
path_match = path.match(matcher)
|
97
|
+
if path_match
|
95
98
|
Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
|
96
99
|
end
|
97
100
|
end
|
data/lib/sidekiq/worker.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'sidekiq/client'
|
3
2
|
|
4
|
-
|
3
|
+
require "sidekiq/client"
|
5
4
|
|
5
|
+
module Sidekiq
|
6
6
|
##
|
7
7
|
# Include this module in your worker class and you can easily create
|
8
8
|
# asynchronous jobs:
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# class HardWorker
|
11
|
+
# include Sidekiq::Worker
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
13
|
+
# def perform(*args)
|
14
|
+
# # do some work
|
15
|
+
# end
|
15
16
|
# end
|
16
|
-
# end
|
17
17
|
#
|
18
18
|
# Then in your Rails app, you can do this:
|
19
19
|
#
|
@@ -21,15 +21,124 @@ module Sidekiq
|
|
21
21
|
#
|
22
22
|
# Note that perform_async is a class method, perform is an instance method.
|
23
23
|
module Worker
|
24
|
+
##
|
25
|
+
# The Options module is extracted so we can include it in ActiveJob::Base
|
26
|
+
# and allow native AJs to configure Sidekiq features/internals.
|
27
|
+
module Options
|
28
|
+
def self.included(base)
|
29
|
+
base.extend(ClassMethods)
|
30
|
+
base.sidekiq_class_attribute :sidekiq_options_hash
|
31
|
+
base.sidekiq_class_attribute :sidekiq_retry_in_block
|
32
|
+
base.sidekiq_class_attribute :sidekiq_retries_exhausted_block
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
ACCESSOR_MUTEX = Mutex.new
|
37
|
+
|
38
|
+
##
|
39
|
+
# Allows customization for this type of Worker.
|
40
|
+
# Legal options:
|
41
|
+
#
|
42
|
+
# queue - name of queue to use for this job type, default *default*
|
43
|
+
# retry - enable retries for this Worker in case of error during execution,
|
44
|
+
# *true* to use the default or *Integer* count
|
45
|
+
# backtrace - whether to save any error backtrace in the retry payload to display in web UI,
|
46
|
+
# can be true, false or an integer number of lines to save, default *false*
|
47
|
+
#
|
48
|
+
# In practice, any option is allowed. This is the main mechanism to configure the
|
49
|
+
# options for a specific job.
|
50
|
+
def sidekiq_options(opts = {})
|
51
|
+
opts = Hash[opts.map { |k, v| [k.to_s, v] }] # stringify
|
52
|
+
self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map { |k, v| [k.to_s, v] }])
|
53
|
+
end
|
54
|
+
|
55
|
+
def sidekiq_retry_in(&block)
|
56
|
+
self.sidekiq_retry_in_block = block
|
57
|
+
end
|
58
|
+
|
59
|
+
def sidekiq_retries_exhausted(&block)
|
60
|
+
self.sidekiq_retries_exhausted_block = block
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_sidekiq_options # :nodoc:
|
64
|
+
self.sidekiq_options_hash ||= Sidekiq.default_worker_options
|
65
|
+
end
|
66
|
+
|
67
|
+
def sidekiq_class_attribute(*attrs)
|
68
|
+
instance_reader = true
|
69
|
+
instance_writer = true
|
70
|
+
|
71
|
+
attrs.each do |name|
|
72
|
+
synchronized_getter = "__synchronized_#{name}"
|
73
|
+
|
74
|
+
singleton_class.instance_eval do
|
75
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
76
|
+
end
|
77
|
+
|
78
|
+
define_singleton_method(synchronized_getter) { nil }
|
79
|
+
singleton_class.class_eval do
|
80
|
+
private(synchronized_getter)
|
81
|
+
end
|
82
|
+
|
83
|
+
define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
|
84
|
+
|
85
|
+
ivar = "@#{name}"
|
86
|
+
|
87
|
+
singleton_class.instance_eval do
|
88
|
+
m = "#{name}="
|
89
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
90
|
+
end
|
91
|
+
define_singleton_method("#{name}=") do |val|
|
92
|
+
singleton_class.class_eval do
|
93
|
+
ACCESSOR_MUTEX.synchronize do
|
94
|
+
undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
|
95
|
+
define_method(synchronized_getter) { val }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if singleton_class?
|
100
|
+
class_eval do
|
101
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
102
|
+
define_method(name) do
|
103
|
+
if instance_variable_defined? ivar
|
104
|
+
instance_variable_get ivar
|
105
|
+
else
|
106
|
+
singleton_class.send name
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
val
|
112
|
+
end
|
113
|
+
|
114
|
+
if instance_reader
|
115
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
116
|
+
define_method(name) do
|
117
|
+
if instance_variable_defined?(ivar)
|
118
|
+
instance_variable_get ivar
|
119
|
+
else
|
120
|
+
self.class.public_send name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if instance_writer
|
126
|
+
m = "#{name}="
|
127
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
128
|
+
attr_writer name
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
24
135
|
attr_accessor :jid
|
25
136
|
|
26
137
|
def self.included(base)
|
27
|
-
raise ArgumentError, "
|
138
|
+
raise ArgumentError, "Sidekiq::Worker cannot be included in an ActiveJob: #{base.name}" if base.ancestors.any? { |c| c.name == "ActiveJob::Base" }
|
28
139
|
|
140
|
+
base.include(Options)
|
29
141
|
base.extend(ClassMethods)
|
30
|
-
base.sidekiq_class_attribute :sidekiq_options_hash
|
31
|
-
base.sidekiq_class_attribute :sidekiq_retry_in_block
|
32
|
-
base.sidekiq_class_attribute :sidekiq_retries_exhausted_block
|
33
142
|
end
|
34
143
|
|
35
144
|
def logger
|
@@ -46,8 +155,13 @@ module Sidekiq
|
|
46
155
|
@opts = opts
|
47
156
|
end
|
48
157
|
|
158
|
+
def set(options)
|
159
|
+
@opts.merge!(options)
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
49
163
|
def perform_async(*args)
|
50
|
-
@klass.client_push(@opts.merge(
|
164
|
+
@klass.client_push(@opts.merge("args" => args, "class" => @klass))
|
51
165
|
end
|
52
166
|
|
53
167
|
# +interval+ must be a timestamp, numeric or something that acts
|
@@ -57,17 +171,15 @@ module Sidekiq
|
|
57
171
|
now = Time.now.to_f
|
58
172
|
ts = (int < 1_000_000_000 ? now + int : int)
|
59
173
|
|
60
|
-
payload = @opts.merge(
|
174
|
+
payload = @opts.merge("class" => @klass, "args" => args, "at" => ts)
|
61
175
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
62
|
-
payload.delete(
|
176
|
+
payload.delete("at") if ts <= now
|
63
177
|
@klass.client_push(payload)
|
64
178
|
end
|
65
179
|
alias_method :perform_at, :perform_in
|
66
180
|
end
|
67
181
|
|
68
182
|
module ClassMethods
|
69
|
-
ACCESSOR_MUTEX = Mutex.new
|
70
|
-
|
71
183
|
def delay(*args)
|
72
184
|
raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
|
73
185
|
end
|
@@ -85,7 +197,7 @@ module Sidekiq
|
|
85
197
|
end
|
86
198
|
|
87
199
|
def perform_async(*args)
|
88
|
-
client_push(
|
200
|
+
client_push("class" => self, "args" => args)
|
89
201
|
end
|
90
202
|
|
91
203
|
# +interval+ must be a timestamp, numeric or something that acts
|
@@ -95,10 +207,10 @@ module Sidekiq
|
|
95
207
|
now = Time.now.to_f
|
96
208
|
ts = (int < 1_000_000_000 ? now + int : int)
|
97
209
|
|
98
|
-
item = {
|
210
|
+
item = {"class" => self, "args" => args, "at" => ts}
|
99
211
|
|
100
212
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
101
|
-
item.delete(
|
213
|
+
item.delete("at") if ts <= now
|
102
214
|
|
103
215
|
client_push(item)
|
104
216
|
end
|
@@ -117,25 +229,12 @@ module Sidekiq
|
|
117
229
|
#
|
118
230
|
# In practice, any option is allowed. This is the main mechanism to configure the
|
119
231
|
# options for a specific job.
|
120
|
-
def sidekiq_options(opts={})
|
121
|
-
|
122
|
-
self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map{|k, v| [k.to_s, v]}])
|
123
|
-
end
|
124
|
-
|
125
|
-
def sidekiq_retry_in(&block)
|
126
|
-
self.sidekiq_retry_in_block = block
|
127
|
-
end
|
128
|
-
|
129
|
-
def sidekiq_retries_exhausted(&block)
|
130
|
-
self.sidekiq_retries_exhausted_block = block
|
131
|
-
end
|
132
|
-
|
133
|
-
def get_sidekiq_options # :nodoc:
|
134
|
-
self.sidekiq_options_hash ||= Sidekiq.default_worker_options
|
232
|
+
def sidekiq_options(opts = {})
|
233
|
+
super
|
135
234
|
end
|
136
235
|
|
137
236
|
def client_push(item) # :nodoc:
|
138
|
-
pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options[
|
237
|
+
pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
|
139
238
|
# stringify
|
140
239
|
item.keys.each do |key|
|
141
240
|
item[key.to_s] = item.delete(key)
|
@@ -143,73 +242,6 @@ module Sidekiq
|
|
143
242
|
|
144
243
|
Sidekiq::Client.new(pool).push(item)
|
145
244
|
end
|
146
|
-
|
147
|
-
def sidekiq_class_attribute(*attrs)
|
148
|
-
instance_reader = true
|
149
|
-
instance_writer = true
|
150
|
-
|
151
|
-
attrs.each do |name|
|
152
|
-
synchronized_getter = "__synchronized_#{name}"
|
153
|
-
|
154
|
-
singleton_class.instance_eval do
|
155
|
-
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
156
|
-
end
|
157
|
-
|
158
|
-
define_singleton_method(synchronized_getter) { nil }
|
159
|
-
singleton_class.class_eval do
|
160
|
-
private(synchronized_getter)
|
161
|
-
end
|
162
|
-
|
163
|
-
define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
|
164
|
-
|
165
|
-
ivar = "@#{name}"
|
166
|
-
|
167
|
-
singleton_class.instance_eval do
|
168
|
-
m = "#{name}="
|
169
|
-
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
170
|
-
end
|
171
|
-
define_singleton_method("#{name}=") do |val|
|
172
|
-
singleton_class.class_eval do
|
173
|
-
ACCESSOR_MUTEX.synchronize do
|
174
|
-
undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
|
175
|
-
define_method(synchronized_getter) { val }
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
if singleton_class?
|
180
|
-
class_eval do
|
181
|
-
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
182
|
-
define_method(name) do
|
183
|
-
if instance_variable_defined? ivar
|
184
|
-
instance_variable_get ivar
|
185
|
-
else
|
186
|
-
singleton_class.send name
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
val
|
192
|
-
end
|
193
|
-
|
194
|
-
if instance_reader
|
195
|
-
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
196
|
-
define_method(name) do
|
197
|
-
if instance_variable_defined?(ivar)
|
198
|
-
instance_variable_get ivar
|
199
|
-
else
|
200
|
-
self.class.public_send name
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
if instance_writer
|
206
|
-
m = "#{name}="
|
207
|
-
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
208
|
-
attr_writer name
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
245
|
end
|
214
246
|
end
|
215
247
|
end
|