sidekiq 4.2.4 → 5.2.10
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 +8 -1
- data/.gitignore +3 -0
- data/.travis.yml +5 -6
- data/5.0-Upgrade.md +56 -0
- data/COMM-LICENSE +12 -10
- data/Changes.md +220 -0
- data/Ent-Changes.md +94 -2
- data/Gemfile +12 -22
- data/LICENSE +1 -1
- data/Pro-4.0-Upgrade.md +35 -0
- data/Pro-Changes.md +176 -2
- data/README.md +10 -7
- data/Rakefile +3 -3
- data/bin/sidekiqctl +13 -92
- data/bin/sidekiqload +16 -34
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
- data/lib/sidekiq/api.rb +166 -68
- data/lib/sidekiq/cli.rb +122 -77
- data/lib/sidekiq/client.rb +25 -18
- data/lib/sidekiq/core_ext.rb +1 -106
- data/lib/sidekiq/ctl.rb +221 -0
- data/lib/sidekiq/delay.rb +42 -0
- data/lib/sidekiq/exception_handler.rb +2 -4
- data/lib/sidekiq/extensions/generic_proxy.rb +7 -1
- data/lib/sidekiq/fetch.rb +1 -1
- data/lib/sidekiq/job_logger.rb +25 -0
- data/lib/sidekiq/job_retry.rb +262 -0
- data/lib/sidekiq/launcher.rb +49 -40
- data/lib/sidekiq/logging.rb +18 -2
- data/lib/sidekiq/manager.rb +6 -7
- data/lib/sidekiq/middleware/server/active_record.rb +10 -0
- data/lib/sidekiq/processor.rb +127 -37
- data/lib/sidekiq/rails.rb +16 -51
- data/lib/sidekiq/redis_connection.rb +50 -5
- data/lib/sidekiq/scheduled.rb +35 -8
- data/lib/sidekiq/testing.rb +24 -7
- data/lib/sidekiq/util.rb +6 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +3 -7
- data/lib/sidekiq/web/application.rb +38 -22
- data/lib/sidekiq/web/helpers.rb +78 -27
- data/lib/sidekiq/web/router.rb +14 -10
- data/lib/sidekiq/web.rb +4 -4
- data/lib/sidekiq/worker.rb +118 -19
- data/lib/sidekiq.rb +27 -26
- data/sidekiq.gemspec +8 -13
- data/web/assets/javascripts/application.js +0 -0
- data/web/assets/javascripts/dashboard.js +33 -18
- data/web/assets/stylesheets/application-rtl.css +246 -0
- data/web/assets/stylesheets/application.css +371 -6
- data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +81 -0
- data/web/locales/en.yml +2 -0
- data/web/locales/es.yml +4 -3
- data/web/locales/fa.yml +80 -0
- data/web/locales/he.yml +79 -0
- data/web/locales/ja.yml +5 -3
- data/web/locales/ur.yml +80 -0
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +1 -1
- data/web/views/_nav.erb +4 -18
- data/web/views/_paging.erb +1 -1
- data/web/views/busy.erb +9 -5
- data/web/views/dashboard.erb +3 -3
- data/web/views/layout.erb +11 -2
- data/web/views/morgue.erb +14 -10
- data/web/views/queue.erb +11 -10
- data/web/views/queues.erb +4 -2
- data/web/views/retries.erb +17 -11
- data/web/views/retry.erb +1 -1
- data/web/views/scheduled.erb +2 -2
- metadata +32 -151
- data/lib/sidekiq/middleware/server/logging.rb +0 -40
- data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -1
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -75
- data/test/test_actors.rb +0 -138
- data/test/test_api.rb +0 -528
- data/test/test_cli.rb +0 -418
- data/test/test_client.rb +0 -266
- data/test/test_exception_handler.rb +0 -56
- data/test/test_extensions.rb +0 -127
- data/test/test_fetch.rb +0 -50
- data/test/test_launcher.rb +0 -95
- data/test/test_logging.rb +0 -35
- data/test/test_manager.rb +0 -50
- data/test/test_middleware.rb +0 -158
- data/test/test_processor.rb +0 -235
- data/test/test_rails.rb +0 -22
- data/test/test_redis_connection.rb +0 -132
- data/test/test_retry.rb +0 -326
- data/test/test_retry_exhausted.rb +0 -149
- data/test/test_scheduled.rb +0 -115
- data/test/test_scheduling.rb +0 -58
- data/test/test_sidekiq.rb +0 -107
- data/test/test_testing.rb +0 -143
- data/test/test_testing_fake.rb +0 -357
- data/test/test_testing_inline.rb +0 -94
- data/test/test_util.rb +0 -13
- data/test/test_web.rb +0 -726
- data/test/test_web_helpers.rb +0 -54
data/lib/sidekiq/worker.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'sidekiq/client'
|
3
|
-
require 'sidekiq/core_ext'
|
4
3
|
|
5
4
|
module Sidekiq
|
6
5
|
|
@@ -8,13 +7,13 @@ module Sidekiq
|
|
8
7
|
# Include this module in your worker class and you can easily create
|
9
8
|
# asynchronous jobs:
|
10
9
|
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# class HardWorker
|
11
|
+
# include Sidekiq::Worker
|
13
12
|
#
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# def perform(*args)
|
14
|
+
# # do some work
|
15
|
+
# end
|
16
16
|
# end
|
17
|
-
# end
|
18
17
|
#
|
19
18
|
# Then in your Rails app, you can do this:
|
20
19
|
#
|
@@ -28,16 +27,51 @@ module Sidekiq
|
|
28
27
|
raise ArgumentError, "You cannot include Sidekiq::Worker in an ActiveJob: #{base.name}" if base.ancestors.any? {|c| c.name == 'ActiveJob::Base' }
|
29
28
|
|
30
29
|
base.extend(ClassMethods)
|
31
|
-
base.
|
32
|
-
base.
|
33
|
-
base.
|
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
|
34
33
|
end
|
35
34
|
|
36
35
|
def logger
|
37
36
|
Sidekiq.logger
|
38
37
|
end
|
39
38
|
|
39
|
+
# This helper class encapsulates the set options for `set`, e.g.
|
40
|
+
#
|
41
|
+
# SomeWorker.set(queue: 'foo').perform_async(....)
|
42
|
+
#
|
43
|
+
class Setter
|
44
|
+
def initialize(klass, opts)
|
45
|
+
@klass = klass
|
46
|
+
@opts = opts
|
47
|
+
end
|
48
|
+
|
49
|
+
def set(options)
|
50
|
+
@opts.merge!(options)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def perform_async(*args)
|
55
|
+
@klass.client_push(@opts.merge('args' => args, 'class' => @klass))
|
56
|
+
end
|
57
|
+
|
58
|
+
# +interval+ must be a timestamp, numeric or something that acts
|
59
|
+
# numeric (like an activesupport time interval).
|
60
|
+
def perform_in(interval, *args)
|
61
|
+
int = interval.to_f
|
62
|
+
now = Time.now.to_f
|
63
|
+
ts = (int < 1_000_000_000 ? now + int : int)
|
64
|
+
|
65
|
+
payload = @opts.merge('class' => @klass, 'args' => args, 'at' => ts)
|
66
|
+
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
67
|
+
payload.delete('at') if ts <= now
|
68
|
+
@klass.client_push(payload)
|
69
|
+
end
|
70
|
+
alias_method :perform_at, :perform_in
|
71
|
+
end
|
72
|
+
|
40
73
|
module ClassMethods
|
74
|
+
ACCESSOR_MUTEX = Mutex.new
|
41
75
|
|
42
76
|
def delay(*args)
|
43
77
|
raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
|
@@ -52,8 +86,7 @@ module Sidekiq
|
|
52
86
|
end
|
53
87
|
|
54
88
|
def set(options)
|
55
|
-
|
56
|
-
self
|
89
|
+
Setter.new(self, options)
|
57
90
|
end
|
58
91
|
|
59
92
|
def perform_async(*args)
|
@@ -70,7 +103,7 @@ module Sidekiq
|
|
70
103
|
item = { 'class' => self, 'args' => args, 'at' => ts }
|
71
104
|
|
72
105
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
73
|
-
item.delete('at'
|
106
|
+
item.delete('at') if ts <= now
|
74
107
|
|
75
108
|
client_push(item)
|
76
109
|
end
|
@@ -90,7 +123,8 @@ module Sidekiq
|
|
90
123
|
# In practice, any option is allowed. This is the main mechanism to configure the
|
91
124
|
# options for a specific job.
|
92
125
|
def sidekiq_options(opts={})
|
93
|
-
|
126
|
+
# stringify
|
127
|
+
self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map{|k, v| [k.to_s, v]}])
|
94
128
|
end
|
95
129
|
|
96
130
|
def sidekiq_retry_in(&block)
|
@@ -107,13 +141,78 @@ module Sidekiq
|
|
107
141
|
|
108
142
|
def client_push(item) # :nodoc:
|
109
143
|
pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options['pool'] || Sidekiq.redis_pool
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
144
|
+
# stringify
|
145
|
+
item.keys.each do |key|
|
146
|
+
item[key.to_s] = item.delete(key)
|
147
|
+
end
|
148
|
+
|
149
|
+
Sidekiq::Client.new(pool).push(item)
|
150
|
+
end
|
151
|
+
|
152
|
+
def sidekiq_class_attribute(*attrs)
|
153
|
+
instance_reader = true
|
154
|
+
instance_writer = true
|
155
|
+
|
156
|
+
attrs.each do |name|
|
157
|
+
synchronized_getter = "__synchronized_#{name}"
|
158
|
+
|
159
|
+
singleton_class.instance_eval do
|
160
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
161
|
+
end
|
162
|
+
|
163
|
+
define_singleton_method(synchronized_getter) { nil }
|
164
|
+
singleton_class.class_eval do
|
165
|
+
private(synchronized_getter)
|
166
|
+
end
|
167
|
+
|
168
|
+
define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
|
169
|
+
|
170
|
+
ivar = "@#{name}"
|
171
|
+
|
172
|
+
singleton_class.instance_eval do
|
173
|
+
m = "#{name}="
|
174
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
175
|
+
end
|
176
|
+
define_singleton_method("#{name}=") do |val|
|
177
|
+
singleton_class.class_eval do
|
178
|
+
ACCESSOR_MUTEX.synchronize do
|
179
|
+
undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
|
180
|
+
define_method(synchronized_getter) { val }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
if singleton_class?
|
185
|
+
class_eval do
|
186
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
187
|
+
define_method(name) do
|
188
|
+
if instance_variable_defined? ivar
|
189
|
+
instance_variable_get ivar
|
190
|
+
else
|
191
|
+
singleton_class.send name
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
val
|
197
|
+
end
|
198
|
+
|
199
|
+
if instance_reader
|
200
|
+
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
201
|
+
define_method(name) do
|
202
|
+
if instance_variable_defined?(ivar)
|
203
|
+
instance_variable_get ivar
|
204
|
+
else
|
205
|
+
self.class.public_send name
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
if instance_writer
|
211
|
+
m = "#{name}="
|
212
|
+
undef_method(m) if method_defined?(m) || private_method_defined?(m)
|
213
|
+
attr_writer name
|
214
|
+
end
|
115
215
|
end
|
116
|
-
Sidekiq::Client.new(pool).push(hash)
|
117
216
|
end
|
118
217
|
|
119
218
|
end
|
data/lib/sidekiq.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
require 'sidekiq/version'
|
4
|
-
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.
|
4
|
+
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.2.2." if RUBY_PLATFORM != 'java' && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
|
5
5
|
|
6
6
|
require 'sidekiq/logging'
|
7
7
|
require 'sidekiq/client'
|
8
8
|
require 'sidekiq/worker'
|
9
9
|
require 'sidekiq/redis_connection'
|
10
|
+
require 'sidekiq/delay'
|
10
11
|
|
11
12
|
require 'json'
|
12
13
|
|
@@ -17,13 +18,14 @@ module Sidekiq
|
|
17
18
|
DEFAULTS = {
|
18
19
|
queues: [],
|
19
20
|
labels: [],
|
20
|
-
concurrency:
|
21
|
+
concurrency: 10,
|
21
22
|
require: '.',
|
22
23
|
environment: nil,
|
23
24
|
timeout: 8,
|
24
25
|
poll_interval_average: nil,
|
25
|
-
average_scheduled_poll_interval:
|
26
|
+
average_scheduled_poll_interval: 5,
|
26
27
|
error_handlers: [],
|
28
|
+
death_handlers: [],
|
27
29
|
lifecycle_events: {
|
28
30
|
startup: [],
|
29
31
|
quiet: [],
|
@@ -46,7 +48,7 @@ module Sidekiq
|
|
46
48
|
"connected_clients" => "9999",
|
47
49
|
"used_memory_human" => "9P",
|
48
50
|
"used_memory_peak_human" => "9P"
|
49
|
-
}
|
51
|
+
}
|
50
52
|
|
51
53
|
def self.❨╯°□°❩╯︵┻━┻
|
52
54
|
puts "Calm down, yo."
|
@@ -55,6 +57,7 @@ module Sidekiq
|
|
55
57
|
def self.options
|
56
58
|
@options ||= DEFAULTS.dup
|
57
59
|
end
|
60
|
+
|
58
61
|
def self.options=(opts)
|
59
62
|
@options = opts
|
60
63
|
end
|
@@ -93,8 +96,8 @@ module Sidekiq
|
|
93
96
|
begin
|
94
97
|
yield conn
|
95
98
|
rescue Redis::CommandError => ex
|
96
|
-
#2550 Failover can cause the server to become a
|
97
|
-
# to disconnect and reopen the socket to get back to the
|
99
|
+
#2550 Failover can cause the server to become a replica, need
|
100
|
+
# to disconnect and reopen the socket to get back to the primary.
|
98
101
|
(conn.disconnect!; retryable = false; retry) if retryable && ex.message =~ /READONLY/
|
99
102
|
raise
|
100
103
|
end
|
@@ -144,32 +147,34 @@ module Sidekiq
|
|
144
147
|
end
|
145
148
|
|
146
149
|
def self.default_server_middleware
|
147
|
-
|
148
|
-
require 'sidekiq/middleware/server/logging'
|
149
|
-
|
150
|
-
Middleware::Chain.new do |m|
|
151
|
-
m.add Middleware::Server::Logging
|
152
|
-
m.add Middleware::Server::RetryJobs
|
153
|
-
end
|
150
|
+
Middleware::Chain.new
|
154
151
|
end
|
155
152
|
|
156
153
|
def self.default_worker_options=(hash)
|
157
|
-
|
154
|
+
# stringify
|
155
|
+
@default_worker_options = default_worker_options.merge(Hash[hash.map{|k, v| [k.to_s, v]}])
|
158
156
|
end
|
159
157
|
def self.default_worker_options
|
160
158
|
defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
|
161
159
|
end
|
162
160
|
|
161
|
+
def self.default_retries_exhausted=(prok)
|
162
|
+
logger.info { "default_retries_exhausted is deprecated, please use `config.death_handlers << -> {|job, ex| }`" }
|
163
|
+
return nil unless prok
|
164
|
+
death_handlers << prok
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Death handlers are called when all retries for a job have been exhausted and
|
169
|
+
# the job dies. It's the notification to your application
|
170
|
+
# that this job will not succeed without manual intervention.
|
171
|
+
#
|
163
172
|
# Sidekiq.configure_server do |config|
|
164
|
-
# config.
|
173
|
+
# config.death_handlers << ->(job, ex) do
|
165
174
|
# end
|
166
175
|
# end
|
167
|
-
def self.
|
168
|
-
|
169
|
-
end
|
170
|
-
@default_retries_exhausted = ->(job, ex) { }
|
171
|
-
def self.default_retries_exhausted
|
172
|
-
@default_retries_exhausted
|
176
|
+
def self.death_handlers
|
177
|
+
options[:death_handlers]
|
173
178
|
end
|
174
179
|
|
175
180
|
def self.load_json(string)
|
@@ -227,10 +232,6 @@ module Sidekiq
|
|
227
232
|
# otherwise Ruby's Thread#kill will commit. See #377.
|
228
233
|
# DO NOT RESCUE THIS ERROR IN YOUR WORKERS
|
229
234
|
class Shutdown < Interrupt; end
|
230
|
-
|
231
235
|
end
|
232
236
|
|
233
|
-
require 'sidekiq/extensions/class_methods'
|
234
|
-
require 'sidekiq/extensions/action_mailer'
|
235
|
-
require 'sidekiq/extensions/active_record'
|
236
237
|
require 'sidekiq/rails' if defined?(::Rails::Engine)
|
data/sidekiq.gemspec
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require File.expand_path('../lib/sidekiq/version', __FILE__)
|
1
|
+
require_relative 'lib/sidekiq/version'
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
5
4
|
gem.authors = ["Mike Perham"]
|
@@ -10,17 +9,13 @@ Gem::Specification.new do |gem|
|
|
10
9
|
gem.license = "LGPL-3.0"
|
11
10
|
|
12
11
|
gem.executables = ['sidekiq', 'sidekiqctl']
|
13
|
-
gem.files = `git ls-files | grep -Ev '^(myapp|examples)'`.split("\n")
|
14
|
-
gem.test_files = `git ls-files -- test/*`.split("\n")
|
12
|
+
gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
|
15
13
|
gem.name = "sidekiq"
|
16
|
-
gem.require_paths = ["lib"]
|
17
14
|
gem.version = Sidekiq::VERSION
|
18
|
-
gem.
|
19
|
-
|
20
|
-
gem.add_dependency
|
21
|
-
gem.add_dependency
|
22
|
-
gem.
|
23
|
-
gem.
|
24
|
-
gem.add_development_dependency 'rake', '~> 10.0'
|
25
|
-
gem.add_development_dependency 'rails', '>= 3.2.0'
|
15
|
+
gem.required_ruby_version = ">= 2.2.2"
|
16
|
+
|
17
|
+
gem.add_dependency "redis", "~> 4.5", "< 4.6.0"
|
18
|
+
gem.add_dependency 'connection_pool', '~> 2.2', '>= 2.2.2'
|
19
|
+
gem.add_dependency 'rack', '~> 2.0'
|
20
|
+
gem.add_dependency 'rack-protection', '>= 1.5.0'
|
26
21
|
end
|
File without changes
|