sidekiq 6.1.2 → 6.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +215 -2
  3. data/LICENSE +3 -3
  4. data/README.md +9 -4
  5. data/bin/sidekiq +3 -3
  6. data/bin/sidekiqload +70 -66
  7. data/bin/sidekiqmon +1 -1
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +321 -145
  13. data/lib/sidekiq/cli.rb +73 -40
  14. data/lib/sidekiq/client.rb +48 -72
  15. data/lib/sidekiq/{util.rb → component.rb} +12 -14
  16. data/lib/sidekiq/delay.rb +3 -1
  17. data/lib/sidekiq/extensions/generic_proxy.rb +4 -2
  18. data/lib/sidekiq/fetch.rb +31 -20
  19. data/lib/sidekiq/job.rb +13 -0
  20. data/lib/sidekiq/job_logger.rb +16 -28
  21. data/lib/sidekiq/job_retry.rb +79 -59
  22. data/lib/sidekiq/job_util.rb +71 -0
  23. data/lib/sidekiq/launcher.rb +126 -65
  24. data/lib/sidekiq/logger.rb +11 -20
  25. data/lib/sidekiq/manager.rb +35 -34
  26. data/lib/sidekiq/metrics/deploy.rb +47 -0
  27. data/lib/sidekiq/metrics/query.rb +153 -0
  28. data/lib/sidekiq/metrics/shared.rb +94 -0
  29. data/lib/sidekiq/metrics/tracking.rb +134 -0
  30. data/lib/sidekiq/middleware/chain.rb +87 -41
  31. data/lib/sidekiq/middleware/current_attributes.rb +63 -0
  32. data/lib/sidekiq/middleware/i18n.rb +6 -4
  33. data/lib/sidekiq/middleware/modules.rb +21 -0
  34. data/lib/sidekiq/monitor.rb +1 -1
  35. data/lib/sidekiq/paginator.rb +8 -8
  36. data/lib/sidekiq/processor.rb +47 -41
  37. data/lib/sidekiq/rails.rb +22 -4
  38. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  39. data/lib/sidekiq/redis_connection.rb +84 -55
  40. data/lib/sidekiq/ring_buffer.rb +29 -0
  41. data/lib/sidekiq/scheduled.rb +55 -25
  42. data/lib/sidekiq/testing/inline.rb +4 -4
  43. data/lib/sidekiq/testing.rb +38 -39
  44. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  45. data/lib/sidekiq/version.rb +1 -1
  46. data/lib/sidekiq/web/action.rb +3 -3
  47. data/lib/sidekiq/web/application.rb +37 -13
  48. data/lib/sidekiq/web/csrf_protection.rb +30 -8
  49. data/lib/sidekiq/web/helpers.rb +60 -28
  50. data/lib/sidekiq/web/router.rb +4 -1
  51. data/lib/sidekiq/web.rb +38 -78
  52. data/lib/sidekiq/worker.rb +136 -13
  53. data/lib/sidekiq.rb +114 -31
  54. data/sidekiq.gemspec +12 -4
  55. data/web/assets/images/apple-touch-icon.png +0 -0
  56. data/web/assets/javascripts/application.js +113 -60
  57. data/web/assets/javascripts/chart.min.js +13 -0
  58. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  59. data/web/assets/javascripts/dashboard.js +50 -67
  60. data/web/assets/javascripts/graph.js +16 -0
  61. data/web/assets/javascripts/metrics.js +262 -0
  62. data/web/assets/stylesheets/application-dark.css +36 -36
  63. data/web/assets/stylesheets/application-rtl.css +0 -4
  64. data/web/assets/stylesheets/application.css +82 -237
  65. data/web/locales/ar.yml +8 -2
  66. data/web/locales/el.yml +43 -19
  67. data/web/locales/en.yml +11 -1
  68. data/web/locales/es.yml +18 -2
  69. data/web/locales/fr.yml +8 -1
  70. data/web/locales/ja.yml +3 -0
  71. data/web/locales/lt.yml +1 -1
  72. data/web/locales/pt-br.yml +27 -9
  73. data/web/views/_footer.erb +1 -1
  74. data/web/views/_job_info.erb +1 -1
  75. data/web/views/_nav.erb +1 -1
  76. data/web/views/_poll_link.erb +2 -5
  77. data/web/views/_summary.erb +7 -7
  78. data/web/views/busy.erb +50 -19
  79. data/web/views/dashboard.erb +23 -14
  80. data/web/views/dead.erb +1 -1
  81. data/web/views/layout.erb +2 -1
  82. data/web/views/metrics.erb +69 -0
  83. data/web/views/metrics_for_job.erb +87 -0
  84. data/web/views/morgue.erb +6 -6
  85. data/web/views/queue.erb +15 -11
  86. data/web/views/queues.erb +3 -3
  87. data/web/views/retries.erb +7 -7
  88. data/web/views/retry.erb +1 -1
  89. data/web/views/scheduled.erb +1 -1
  90. metadata +43 -36
  91. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
  92. data/.github/contributing.md +0 -32
  93. data/.github/workflows/ci.yml +0 -41
  94. data/.gitignore +0 -13
  95. data/.standard.yml +0 -20
  96. data/3.0-Upgrade.md +0 -70
  97. data/4.0-Upgrade.md +0 -53
  98. data/5.0-Upgrade.md +0 -56
  99. data/6.0-Upgrade.md +0 -72
  100. data/COMM-LICENSE +0 -97
  101. data/Ent-2.0-Upgrade.md +0 -37
  102. data/Ent-Changes.md +0 -281
  103. data/Gemfile +0 -24
  104. data/Gemfile.lock +0 -192
  105. data/Pro-2.0-Upgrade.md +0 -138
  106. data/Pro-3.0-Upgrade.md +0 -44
  107. data/Pro-4.0-Upgrade.md +0 -35
  108. data/Pro-5.0-Upgrade.md +0 -25
  109. data/Pro-Changes.md +0 -805
  110. data/Rakefile +0 -10
  111. data/code_of_conduct.md +0 -50
  112. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  113. data/lib/sidekiq/exception_handler.rb +0 -27
data/lib/sidekiq.rb CHANGED
@@ -5,7 +5,9 @@ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.5.0." i
5
5
 
6
6
  require "sidekiq/logger"
7
7
  require "sidekiq/client"
8
+ require "sidekiq/transaction_aware_client"
8
9
  require "sidekiq/worker"
10
+ require "sidekiq/job"
9
11
  require "sidekiq/redis_connection"
10
12
  require "sidekiq/delay"
11
13
 
@@ -25,24 +27,23 @@ module Sidekiq
25
27
  timeout: 25,
26
28
  poll_interval_average: nil,
27
29
  average_scheduled_poll_interval: 5,
30
+ on_complex_arguments: :warn,
28
31
  error_handlers: [],
29
32
  death_handlers: [],
30
33
  lifecycle_events: {
31
34
  startup: [],
32
35
  quiet: [],
33
36
  shutdown: [],
34
- heartbeat: []
37
+ # triggers when we fire the first heartbeat on startup OR repairing a network partition
38
+ heartbeat: [],
39
+ # triggers on EVERY heartbeat call, every 10 seconds
40
+ beat: []
35
41
  },
36
42
  dead_max_jobs: 10_000,
37
43
  dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
38
44
  reloader: proc { |&block| block.call }
39
45
  }
40
46
 
41
- DEFAULT_WORKER_OPTIONS = {
42
- "retry" => true,
43
- "queue" => "default"
44
- }
45
-
46
47
  FAKE_INFO = {
47
48
  "redis_version" => "9.9.9",
48
49
  "uptime_in_days" => "9999",
@@ -55,19 +56,84 @@ module Sidekiq
55
56
  puts "Calm down, yo."
56
57
  end
57
58
 
59
+ # config.concurrency = 5
60
+ def self.concurrency=(val)
61
+ self[:concurrency] = Integer(val)
62
+ end
63
+
64
+ # config.queues = %w( high default low ) # strict
65
+ # config.queues = %w( high,3 default,2 low,1 ) # weighted
66
+ # config.queues = %w( feature1,1 feature2,1 feature3,1 ) # random
67
+ #
68
+ # With weighted priority, queue will be checked first (weight / total) of the time.
69
+ # high will be checked first (3/6) or 50% of the time.
70
+ # I'd recommend setting weights between 1-10. Weights in the hundreds or thousands
71
+ # are ridiculous and unnecessarily expensive. You can get random queue ordering
72
+ # by explicitly setting all weights to 1.
73
+ def self.queues=(val)
74
+ self[:queues] = Array(val).each_with_object([]) do |qstr, memo|
75
+ name, weight = qstr.split(",")
76
+ self[:strict] = false if weight.to_i > 0
77
+ [weight.to_i, 1].max.times do
78
+ memo << name
79
+ end
80
+ end
81
+ end
82
+
83
+ ### Private APIs
84
+ def self.default_error_handler(ex, ctx)
85
+ logger.warn(dump_json(ctx)) unless ctx.empty?
86
+ logger.warn("#{ex.class.name}: #{ex.message}")
87
+ logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
88
+ end
89
+
90
+ # DEFAULT_ERROR_HANDLER is a constant that allows the default error handler to
91
+ # be referenced. It must be defined here, after the default_error_handler
92
+ # method is defined.
93
+ DEFAULT_ERROR_HANDLER = method(:default_error_handler)
94
+
95
+ @config = DEFAULTS.dup
58
96
  def self.options
59
- @options ||= DEFAULTS.dup
97
+ logger.warn "`config.options[:key] = value` is deprecated, use `config[:key] = value`: #{caller(1..2)}"
98
+ @config
60
99
  end
61
100
 
62
101
  def self.options=(opts)
63
- @options = opts
102
+ logger.warn "config.options = hash` is deprecated, use `config.merge!(hash)`: #{caller(1..2)}"
103
+ @config = opts
104
+ end
105
+
106
+ def self.[](key)
107
+ @config[key]
108
+ end
109
+
110
+ def self.[]=(key, val)
111
+ @config[key] = val
64
112
  end
65
113
 
114
+ def self.merge!(hash)
115
+ @config.merge!(hash)
116
+ end
117
+
118
+ def self.fetch(*args, &block)
119
+ @config.fetch(*args, &block)
120
+ end
121
+
122
+ def self.handle_exception(ex, ctx = {})
123
+ self[:error_handlers].each do |handler|
124
+ handler.call(ex, ctx)
125
+ rescue => ex
126
+ logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
127
+ logger.error ex
128
+ logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
129
+ end
130
+ end
131
+ ###
132
+
66
133
  ##
67
134
  # Configuration for Sidekiq server, use like:
68
135
  #
69
136
  # Sidekiq.configure_server do |config|
70
- # config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
71
137
  # config.server_middleware do |chain|
72
138
  # chain.add MyServerHook
73
139
  # end
@@ -80,7 +146,7 @@ module Sidekiq
80
146
  # Configuration for Sidekiq client, use like:
81
147
  #
82
148
  # Sidekiq.configure_client do |config|
83
- # config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
149
+ # config.redis = { size: 1, url: 'redis://myhost:8877/0' }
84
150
  # end
85
151
  def self.configure_client
86
152
  yield self unless server?
@@ -96,11 +162,13 @@ module Sidekiq
96
162
  retryable = true
97
163
  begin
98
164
  yield conn
99
- rescue Redis::BaseError => ex
165
+ rescue RedisConnection.adapter::BaseError => ex
100
166
  # 2550 Failover can cause the server to become a replica, need
101
167
  # to disconnect and reopen the socket to get back to the primary.
102
168
  # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
103
- if retryable && ex.message =~ /READONLY|NOREPLICAS/
169
+ # 4985 Use the same logic when a blocking command is force-unblocked
170
+ # The same retry logic is also used in client.rb
171
+ if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
104
172
  conn.disconnect!
105
173
  retryable = false
106
174
  retry
@@ -119,7 +187,7 @@ module Sidekiq
119
187
  else
120
188
  conn.info
121
189
  end
122
- rescue Redis::CommandError => ex
190
+ rescue RedisConnection.adapter::CommandError => ex
123
191
  # 2850 return fake version when INFO command has (probably) been renamed
124
192
  raise unless /unknown command/.match?(ex.message)
125
193
  FAKE_INFO
@@ -127,19 +195,19 @@ module Sidekiq
127
195
  end
128
196
 
129
197
  def self.redis_pool
130
- @redis ||= Sidekiq::RedisConnection.create
198
+ @redis ||= RedisConnection.create
131
199
  end
132
200
 
133
201
  def self.redis=(hash)
134
202
  @redis = if hash.is_a?(ConnectionPool)
135
203
  hash
136
204
  else
137
- Sidekiq::RedisConnection.create(hash)
205
+ RedisConnection.create(hash)
138
206
  end
139
207
  end
140
208
 
141
209
  def self.client_middleware
142
- @client_chain ||= Middleware::Chain.new
210
+ @client_chain ||= Middleware::Chain.new(self)
143
211
  yield @client_chain if block_given?
144
212
  @client_chain
145
213
  end
@@ -151,16 +219,23 @@ module Sidekiq
151
219
  end
152
220
 
153
221
  def self.default_server_middleware
154
- Middleware::Chain.new
222
+ Middleware::Chain.new(self)
155
223
  end
156
224
 
157
- def self.default_worker_options=(hash)
158
- # stringify
159
- @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
225
+ def self.default_worker_options=(hash) # deprecated
226
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
160
227
  end
161
228
 
162
- def self.default_worker_options
163
- defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
229
+ def self.default_job_options=(hash)
230
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
231
+ end
232
+
233
+ def self.default_worker_options # deprecated
234
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
235
+ end
236
+
237
+ def self.default_job_options
238
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
164
239
  end
165
240
 
166
241
  ##
@@ -173,7 +248,7 @@ module Sidekiq
173
248
  # end
174
249
  # end
175
250
  def self.death_handlers
176
- options[:death_handlers]
251
+ self[:death_handlers]
177
252
  end
178
253
 
179
254
  def self.load_json(string)
@@ -198,7 +273,7 @@ module Sidekiq
198
273
  end
199
274
 
200
275
  def self.logger
201
- @logger ||= Sidekiq::Logger.new($stdout, level: Logger::INFO)
276
+ @logger ||= Sidekiq::Logger.new($stdout, level: :info)
202
277
  end
203
278
 
204
279
  def self.logger=(logger)
@@ -216,13 +291,17 @@ module Sidekiq
216
291
  defined?(Sidekiq::Pro)
217
292
  end
218
293
 
294
+ def self.ent?
295
+ defined?(Sidekiq::Enterprise)
296
+ end
297
+
219
298
  # How frequently Redis should be checked by a random Sidekiq process for
220
299
  # scheduled and retriable jobs. Each individual process will take turns by
221
300
  # waiting some multiple of this value.
222
301
  #
223
302
  # See sidekiq/scheduled.rb for an in-depth explanation of this value
224
303
  def self.average_scheduled_poll_interval=(interval)
225
- options[:average_scheduled_poll_interval] = interval
304
+ self[:average_scheduled_poll_interval] = interval
226
305
  end
227
306
 
228
307
  # Register a proc to handle any error which occurs within the Sidekiq process.
@@ -233,7 +312,7 @@ module Sidekiq
233
312
  #
234
313
  # The default error handler logs errors to Sidekiq.logger.
235
314
  def self.error_handlers
236
- options[:error_handlers]
315
+ self[:error_handlers]
237
316
  end
238
317
 
239
318
  # Register a block to run at a point in the Sidekiq lifecycle.
@@ -246,16 +325,20 @@ module Sidekiq
246
325
  # end
247
326
  def self.on(event, &block)
248
327
  raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
249
- raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
250
- options[:lifecycle_events][event] << block
328
+ raise ArgumentError, "Invalid event name: #{event}" unless self[:lifecycle_events].key?(event)
329
+ self[:lifecycle_events][event] << block
330
+ end
331
+
332
+ def self.strict_args!(mode = :raise)
333
+ self[:on_complex_arguments] = mode
251
334
  end
252
335
 
253
- # We are shutting down Sidekiq but what about workers that
336
+ # We are shutting down Sidekiq but what about threads that
254
337
  # are working on some long job? This error is
255
- # raised in workers that have not finished within the hard
338
+ # raised in jobs that have not finished within the hard
256
339
  # timeout limit. This is needed to rollback db transactions,
257
340
  # otherwise Ruby's Thread#kill will commit. See #377.
258
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
341
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
259
342
  class Shutdown < Interrupt; end
260
343
  end
261
344
 
data/sidekiq.gemspec CHANGED
@@ -5,16 +5,24 @@ Gem::Specification.new do |gem|
5
5
  gem.email = ["mperham@gmail.com"]
6
6
  gem.summary = "Simple, efficient background processing for Ruby"
7
7
  gem.description = "Simple, efficient background processing for Ruby."
8
- gem.homepage = "http://sidekiq.org"
8
+ gem.homepage = "https://sidekiq.org"
9
9
  gem.license = "LGPL-3.0"
10
10
 
11
11
  gem.executables = ["sidekiq", "sidekiqmon"]
12
- gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
12
+ gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n")
13
13
  gem.name = "sidekiq"
14
14
  gem.version = Sidekiq::VERSION
15
15
  gem.required_ruby_version = ">= 2.5.0"
16
16
 
17
- gem.add_dependency "redis", ">= 4.2.0"
18
- gem.add_dependency "connection_pool", ">= 2.2.2"
17
+ gem.metadata = {
18
+ "homepage_uri" => "https://sidekiq.org",
19
+ "bug_tracker_uri" => "https://github.com/mperham/sidekiq/issues",
20
+ "documentation_uri" => "https://github.com/mperham/sidekiq/wiki",
21
+ "changelog_uri" => "https://github.com/mperham/sidekiq/blob/main/Changes.md",
22
+ "source_code_uri" => "https://github.com/mperham/sidekiq"
23
+ }
24
+
25
+ gem.add_dependency "redis", "<5", ">= 4.5.0"
26
+ gem.add_dependency "connection_pool", ">= 2.2.5"
19
27
  gem.add_dependency "rack", "~> 2.0"
20
28
  end