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.

Files changed (108) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +61 -0
  3. data/.github/issue_template.md +8 -1
  4. data/.gitignore +3 -0
  5. data/.travis.yml +5 -6
  6. data/5.0-Upgrade.md +56 -0
  7. data/COMM-LICENSE +12 -10
  8. data/Changes.md +220 -0
  9. data/Ent-Changes.md +94 -2
  10. data/Gemfile +12 -22
  11. data/LICENSE +1 -1
  12. data/Pro-4.0-Upgrade.md +35 -0
  13. data/Pro-Changes.md +176 -2
  14. data/README.md +10 -7
  15. data/Rakefile +3 -3
  16. data/bin/sidekiqctl +13 -92
  17. data/bin/sidekiqload +16 -34
  18. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
  19. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  20. data/lib/sidekiq/api.rb +166 -68
  21. data/lib/sidekiq/cli.rb +122 -77
  22. data/lib/sidekiq/client.rb +25 -18
  23. data/lib/sidekiq/core_ext.rb +1 -106
  24. data/lib/sidekiq/ctl.rb +221 -0
  25. data/lib/sidekiq/delay.rb +42 -0
  26. data/lib/sidekiq/exception_handler.rb +2 -4
  27. data/lib/sidekiq/extensions/generic_proxy.rb +7 -1
  28. data/lib/sidekiq/fetch.rb +1 -1
  29. data/lib/sidekiq/job_logger.rb +25 -0
  30. data/lib/sidekiq/job_retry.rb +262 -0
  31. data/lib/sidekiq/launcher.rb +49 -40
  32. data/lib/sidekiq/logging.rb +18 -2
  33. data/lib/sidekiq/manager.rb +6 -7
  34. data/lib/sidekiq/middleware/server/active_record.rb +10 -0
  35. data/lib/sidekiq/processor.rb +127 -37
  36. data/lib/sidekiq/rails.rb +16 -51
  37. data/lib/sidekiq/redis_connection.rb +50 -5
  38. data/lib/sidekiq/scheduled.rb +35 -8
  39. data/lib/sidekiq/testing.rb +24 -7
  40. data/lib/sidekiq/util.rb +6 -2
  41. data/lib/sidekiq/version.rb +1 -1
  42. data/lib/sidekiq/web/action.rb +3 -7
  43. data/lib/sidekiq/web/application.rb +38 -22
  44. data/lib/sidekiq/web/helpers.rb +78 -27
  45. data/lib/sidekiq/web/router.rb +14 -10
  46. data/lib/sidekiq/web.rb +4 -4
  47. data/lib/sidekiq/worker.rb +118 -19
  48. data/lib/sidekiq.rb +27 -26
  49. data/sidekiq.gemspec +8 -13
  50. data/web/assets/javascripts/application.js +0 -0
  51. data/web/assets/javascripts/dashboard.js +33 -18
  52. data/web/assets/stylesheets/application-rtl.css +246 -0
  53. data/web/assets/stylesheets/application.css +371 -6
  54. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  55. data/web/assets/stylesheets/bootstrap.css +2 -2
  56. data/web/locales/ar.yml +81 -0
  57. data/web/locales/en.yml +2 -0
  58. data/web/locales/es.yml +4 -3
  59. data/web/locales/fa.yml +80 -0
  60. data/web/locales/he.yml +79 -0
  61. data/web/locales/ja.yml +5 -3
  62. data/web/locales/ur.yml +80 -0
  63. data/web/views/_footer.erb +5 -2
  64. data/web/views/_job_info.erb +1 -1
  65. data/web/views/_nav.erb +4 -18
  66. data/web/views/_paging.erb +1 -1
  67. data/web/views/busy.erb +9 -5
  68. data/web/views/dashboard.erb +3 -3
  69. data/web/views/layout.erb +11 -2
  70. data/web/views/morgue.erb +14 -10
  71. data/web/views/queue.erb +11 -10
  72. data/web/views/queues.erb +4 -2
  73. data/web/views/retries.erb +17 -11
  74. data/web/views/retry.erb +1 -1
  75. data/web/views/scheduled.erb +2 -2
  76. metadata +32 -151
  77. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  78. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  79. data/test/config.yml +0 -9
  80. data/test/env_based_config.yml +0 -11
  81. data/test/fake_env.rb +0 -1
  82. data/test/fixtures/en.yml +0 -2
  83. data/test/helper.rb +0 -75
  84. data/test/test_actors.rb +0 -138
  85. data/test/test_api.rb +0 -528
  86. data/test/test_cli.rb +0 -418
  87. data/test/test_client.rb +0 -266
  88. data/test/test_exception_handler.rb +0 -56
  89. data/test/test_extensions.rb +0 -127
  90. data/test/test_fetch.rb +0 -50
  91. data/test/test_launcher.rb +0 -95
  92. data/test/test_logging.rb +0 -35
  93. data/test/test_manager.rb +0 -50
  94. data/test/test_middleware.rb +0 -158
  95. data/test/test_processor.rb +0 -235
  96. data/test/test_rails.rb +0 -22
  97. data/test/test_redis_connection.rb +0 -132
  98. data/test/test_retry.rb +0 -326
  99. data/test/test_retry_exhausted.rb +0 -149
  100. data/test/test_scheduled.rb +0 -115
  101. data/test/test_scheduling.rb +0 -58
  102. data/test/test_sidekiq.rb +0 -107
  103. data/test/test_testing.rb +0 -143
  104. data/test/test_testing_fake.rb +0 -357
  105. data/test/test_testing_inline.rb +0 -94
  106. data/test/test_util.rb +0 -13
  107. data/test/test_web.rb +0 -726
  108. data/test/test_web_helpers.rb +0 -54
@@ -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
- # class HardWorker
12
- # include Sidekiq::Worker
10
+ # class HardWorker
11
+ # include Sidekiq::Worker
13
12
  #
14
- # def perform(*args)
15
- # # do some work
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.class_attribute :sidekiq_options_hash
32
- base.class_attribute :sidekiq_retry_in_block
33
- base.class_attribute :sidekiq_retries_exhausted_block
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
- Thread.current[:sidekiq_worker_set] = options
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'.freeze) if ts <= now
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
- self.sidekiq_options_hash = get_sidekiq_options.merge(opts.stringify_keys)
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
- hash = if Thread.current[:sidekiq_worker_set]
111
- x, Thread.current[:sidekiq_worker_set] = Thread.current[:sidekiq_worker_set], nil
112
- x.stringify_keys.merge(item.stringify_keys)
113
- else
114
- item.stringify_keys
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
- # encoding: utf-8
2
+
3
3
  require 'sidekiq/version'
4
- fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.0.0." if RUBY_PLATFORM != 'java' && RUBY_VERSION < '2.0.0'
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: 25,
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: 15,
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
- }.freeze
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 slave, need
97
- # to disconnect and reopen the socket to get back to the master.
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
- require 'sidekiq/middleware/server/retry_jobs'
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
- @default_worker_options = default_worker_options.merge(hash.stringify_keys)
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.default_retries_exhausted = -> (job, ex) do
173
+ # config.death_handlers << ->(job, ex) do
165
174
  # end
166
175
  # end
167
- def self.default_retries_exhausted=(prok)
168
- @default_retries_exhausted = prok
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
- # -*- encoding: utf-8 -*-
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.add_dependency 'redis', '~> 3.2', '>= 3.2.1'
19
- gem.add_dependency 'connection_pool', '~> 2.2', '>= 2.2.0'
20
- gem.add_dependency 'concurrent-ruby', '~> 1.0'
21
- gem.add_dependency 'rack-protection', '>= 1.5.0'
22
- gem.add_development_dependency 'redis-namespace', '~> 1.5', '>= 1.5.2'
23
- gem.add_development_dependency 'minitest', '~> 5.7', '>= 5.7.0'
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