sidekiq 4.2.10 → 7.3.10

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.
Files changed (159) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +932 -7
  3. data/LICENSE.txt +9 -0
  4. data/README.md +49 -50
  5. data/bin/multi_queue_bench +271 -0
  6. data/bin/sidekiq +22 -3
  7. data/bin/sidekiqload +218 -116
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +75 -0
  10. data/lib/generators/sidekiq/job_generator.rb +59 -0
  11. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  12. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  13. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  14. data/lib/sidekiq/api.rb +710 -322
  15. data/lib/sidekiq/capsule.rb +132 -0
  16. data/lib/sidekiq/cli.rb +268 -248
  17. data/lib/sidekiq/client.rb +153 -101
  18. data/lib/sidekiq/component.rb +90 -0
  19. data/lib/sidekiq/config.rb +311 -0
  20. data/lib/sidekiq/deploy.rb +64 -0
  21. data/lib/sidekiq/embedded.rb +63 -0
  22. data/lib/sidekiq/fetch.rb +50 -42
  23. data/lib/sidekiq/iterable_job.rb +55 -0
  24. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  25. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  26. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  27. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  28. data/lib/sidekiq/job/iterable.rb +294 -0
  29. data/lib/sidekiq/job.rb +385 -0
  30. data/lib/sidekiq/job_logger.rb +52 -0
  31. data/lib/sidekiq/job_retry.rb +305 -0
  32. data/lib/sidekiq/job_util.rb +109 -0
  33. data/lib/sidekiq/launcher.rb +208 -108
  34. data/lib/sidekiq/logger.rb +131 -0
  35. data/lib/sidekiq/manager.rb +43 -47
  36. data/lib/sidekiq/metrics/query.rb +158 -0
  37. data/lib/sidekiq/metrics/shared.rb +106 -0
  38. data/lib/sidekiq/metrics/tracking.rb +148 -0
  39. data/lib/sidekiq/middleware/chain.rb +113 -56
  40. data/lib/sidekiq/middleware/current_attributes.rb +128 -0
  41. data/lib/sidekiq/middleware/i18n.rb +9 -7
  42. data/lib/sidekiq/middleware/modules.rb +23 -0
  43. data/lib/sidekiq/monitor.rb +147 -0
  44. data/lib/sidekiq/paginator.rb +33 -15
  45. data/lib/sidekiq/processor.rb +188 -98
  46. data/lib/sidekiq/rails.rb +53 -92
  47. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  48. data/lib/sidekiq/redis_connection.rb +86 -77
  49. data/lib/sidekiq/ring_buffer.rb +32 -0
  50. data/lib/sidekiq/scheduled.rb +140 -51
  51. data/lib/sidekiq/sd_notify.rb +149 -0
  52. data/lib/sidekiq/systemd.rb +26 -0
  53. data/lib/sidekiq/testing/inline.rb +6 -5
  54. data/lib/sidekiq/testing.rb +95 -85
  55. data/lib/sidekiq/transaction_aware_client.rb +59 -0
  56. data/lib/sidekiq/version.rb +7 -1
  57. data/lib/sidekiq/web/action.rb +40 -18
  58. data/lib/sidekiq/web/application.rb +189 -89
  59. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  60. data/lib/sidekiq/web/helpers.rb +239 -101
  61. data/lib/sidekiq/web/router.rb +28 -21
  62. data/lib/sidekiq/web.rb +123 -110
  63. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  64. data/lib/sidekiq.rb +97 -185
  65. data/sidekiq.gemspec +26 -27
  66. data/web/assets/images/apple-touch-icon.png +0 -0
  67. data/web/assets/javascripts/application.js +157 -61
  68. data/web/assets/javascripts/base-charts.js +106 -0
  69. data/web/assets/javascripts/chart.min.js +13 -0
  70. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  71. data/web/assets/javascripts/dashboard-charts.js +194 -0
  72. data/web/assets/javascripts/dashboard.js +43 -280
  73. data/web/assets/javascripts/metrics.js +298 -0
  74. data/web/assets/stylesheets/application-dark.css +147 -0
  75. data/web/assets/stylesheets/application-rtl.css +163 -0
  76. data/web/assets/stylesheets/application.css +176 -196
  77. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  78. data/web/assets/stylesheets/bootstrap.css +2 -2
  79. data/web/locales/ar.yml +87 -0
  80. data/web/locales/cs.yml +62 -62
  81. data/web/locales/da.yml +60 -53
  82. data/web/locales/de.yml +65 -53
  83. data/web/locales/el.yml +43 -24
  84. data/web/locales/en.yml +88 -64
  85. data/web/locales/es.yml +70 -53
  86. data/web/locales/fa.yml +65 -64
  87. data/web/locales/fr.yml +82 -62
  88. data/web/locales/gd.yml +98 -0
  89. data/web/locales/he.yml +80 -0
  90. data/web/locales/hi.yml +59 -59
  91. data/web/locales/it.yml +85 -54
  92. data/web/locales/ja.yml +74 -62
  93. data/web/locales/ko.yml +52 -52
  94. data/web/locales/lt.yml +83 -0
  95. data/web/locales/nb.yml +61 -61
  96. data/web/locales/nl.yml +52 -52
  97. data/web/locales/pl.yml +45 -45
  98. data/web/locales/pt-br.yml +82 -55
  99. data/web/locales/pt.yml +51 -51
  100. data/web/locales/ru.yml +68 -63
  101. data/web/locales/sv.yml +53 -53
  102. data/web/locales/ta.yml +60 -60
  103. data/web/locales/tr.yml +100 -0
  104. data/web/locales/uk.yml +85 -61
  105. data/web/locales/ur.yml +80 -0
  106. data/web/locales/vi.yml +83 -0
  107. data/web/locales/zh-cn.yml +42 -16
  108. data/web/locales/zh-tw.yml +41 -8
  109. data/web/views/_footer.erb +20 -3
  110. data/web/views/_job_info.erb +21 -4
  111. data/web/views/_metrics_period_select.erb +12 -0
  112. data/web/views/_nav.erb +5 -19
  113. data/web/views/_paging.erb +3 -1
  114. data/web/views/_poll_link.erb +3 -6
  115. data/web/views/_summary.erb +7 -7
  116. data/web/views/busy.erb +85 -31
  117. data/web/views/dashboard.erb +53 -20
  118. data/web/views/dead.erb +3 -3
  119. data/web/views/filtering.erb +6 -0
  120. data/web/views/layout.erb +17 -6
  121. data/web/views/metrics.erb +90 -0
  122. data/web/views/metrics_for_job.erb +59 -0
  123. data/web/views/morgue.erb +15 -16
  124. data/web/views/queue.erb +35 -25
  125. data/web/views/queues.erb +20 -4
  126. data/web/views/retries.erb +19 -16
  127. data/web/views/retry.erb +3 -3
  128. data/web/views/scheduled.erb +19 -17
  129. metadata +103 -194
  130. data/.github/contributing.md +0 -32
  131. data/.github/issue_template.md +0 -9
  132. data/.gitignore +0 -12
  133. data/.travis.yml +0 -18
  134. data/3.0-Upgrade.md +0 -70
  135. data/4.0-Upgrade.md +0 -53
  136. data/COMM-LICENSE +0 -95
  137. data/Ent-Changes.md +0 -173
  138. data/Gemfile +0 -29
  139. data/LICENSE +0 -9
  140. data/Pro-2.0-Upgrade.md +0 -138
  141. data/Pro-3.0-Upgrade.md +0 -44
  142. data/Pro-Changes.md +0 -628
  143. data/Rakefile +0 -12
  144. data/bin/sidekiqctl +0 -99
  145. data/code_of_conduct.md +0 -50
  146. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  147. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  148. data/lib/sidekiq/core_ext.rb +0 -119
  149. data/lib/sidekiq/exception_handler.rb +0 -31
  150. data/lib/sidekiq/extensions/action_mailer.rb +0 -57
  151. data/lib/sidekiq/extensions/active_record.rb +0 -40
  152. data/lib/sidekiq/extensions/class_methods.rb +0 -40
  153. data/lib/sidekiq/extensions/generic_proxy.rb +0 -25
  154. data/lib/sidekiq/logging.rb +0 -106
  155. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  156. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  157. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  158. data/lib/sidekiq/util.rb +0 -63
  159. data/lib/sidekiq/worker.rb +0 -121
data/lib/sidekiq/web.rb CHANGED
@@ -1,49 +1,62 @@
1
1
  # frozen_string_literal: true
2
- require 'erb'
3
2
 
4
- require 'sidekiq'
5
- require 'sidekiq/api'
6
- require 'sidekiq/paginator'
7
- require 'sidekiq/web/helpers'
3
+ require "erb"
4
+ require "securerandom"
8
5
 
9
- require 'sidekiq/web/router'
10
- require 'sidekiq/web/action'
11
- require 'sidekiq/web/application'
6
+ require "sidekiq"
7
+ require "sidekiq/api"
8
+ require "sidekiq/paginator"
9
+ require "sidekiq/web/helpers"
12
10
 
13
- require 'rack/protection'
11
+ require "sidekiq/web/router"
12
+ require "sidekiq/web/action"
13
+ require "sidekiq/web/application"
14
+ require "sidekiq/web/csrf_protection"
14
15
 
15
- require 'rack/builder'
16
- require 'rack/file'
17
- require 'rack/session/cookie'
16
+ require "rack/content_length"
17
+ require "rack/builder"
18
+ require "rack/static"
18
19
 
19
20
  module Sidekiq
20
21
  class Web
21
22
  ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../web")
22
- VIEWS = "#{ROOT}/views".freeze
23
- LOCALES = ["#{ROOT}/locales".freeze]
24
- LAYOUT = "#{VIEWS}/layout.erb".freeze
25
- ASSETS = "#{ROOT}/assets".freeze
23
+ VIEWS = "#{ROOT}/views"
24
+ LOCALES = ["#{ROOT}/locales"]
25
+ LAYOUT = "#{VIEWS}/layout.erb"
26
+ ASSETS = "#{ROOT}/assets"
26
27
 
27
28
  DEFAULT_TABS = {
28
- "Dashboard" => '',
29
- "Busy" => 'busy',
30
- "Queues" => 'queues',
31
- "Retries" => 'retries',
32
- "Scheduled" => 'scheduled',
33
- "Dead" => 'morgue',
29
+ "Dashboard" => "",
30
+ "Busy" => "busy",
31
+ "Queues" => "queues",
32
+ "Retries" => "retries",
33
+ "Scheduled" => "scheduled",
34
+ "Dead" => "morgue",
35
+ "Metrics" => "metrics"
34
36
  }
35
37
 
36
- class << self
37
- def settings
38
- self
39
- end
38
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
39
+ CONTENT_LANGUAGE = "Content-Language"
40
+ CONTENT_SECURITY_POLICY = "Content-Security-Policy"
41
+ LOCATION = "Location"
42
+ X_CASCADE = "X-Cascade"
43
+ X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options"
44
+ else
45
+ CONTENT_LANGUAGE = "content-language"
46
+ CONTENT_SECURITY_POLICY = "content-security-policy"
47
+ LOCATION = "location"
48
+ X_CASCADE = "x-cascade"
49
+ X_CONTENT_TYPE_OPTIONS = "x-content-type-options"
50
+ end
40
51
 
41
- def middlewares
42
- @middlewares ||= []
52
+ class << self
53
+ # Forward compatibility with 8.0
54
+ def configure
55
+ yield self
43
56
  end
44
57
 
45
- def use(*middleware_args, &block)
46
- middlewares << [middleware_args, block]
58
+ def settings
59
+ self
47
60
  end
48
61
 
49
62
  def default_tabs
@@ -55,6 +68,10 @@ module Sidekiq
55
68
  end
56
69
  alias_method :tabs, :custom_tabs
57
70
 
71
+ def custom_job_info_rows
72
+ @custom_job_info_rows ||= []
73
+ end
74
+
58
75
  def locales
59
76
  @locales ||= LOCALES
60
77
  end
@@ -64,42 +81,48 @@ module Sidekiq
64
81
  end
65
82
 
66
83
  def enable(*opts)
67
- opts.each {|key| set(key, true) }
84
+ opts.each { |key| set(key, true) }
68
85
  end
69
86
 
70
87
  def disable(*opts)
71
- opts.each {|key| set(key, false) }
88
+ opts.each { |key| set(key, false) }
89
+ end
90
+
91
+ def middlewares
92
+ @middlewares ||= []
93
+ end
94
+
95
+ def use(*args, &block)
96
+ middlewares << [args, block]
72
97
  end
73
98
 
74
- # Helper for the Sinatra syntax: Sidekiq::Web.set(:session_secret, Rails.application.secrets...)
75
99
  def set(attribute, value)
76
100
  send(:"#{attribute}=", value)
77
101
  end
78
102
 
79
- attr_accessor :app_url, :session_secret, :redis_pool, :sessions
103
+ attr_accessor :app_url, :redis_pool
80
104
  attr_writer :locales, :views
81
105
  end
82
106
 
83
107
  def self.inherited(child)
84
- child.app_url = self.app_url
85
- child.session_secret = self.session_secret
86
- child.redis_pool = self.redis_pool
87
- child.sessions = self.sessions
108
+ child.app_url = app_url
109
+ child.redis_pool = redis_pool
88
110
  end
89
111
 
90
112
  def settings
91
113
  self.class.settings
92
114
  end
93
115
 
94
- def use(*middleware_args, &block)
95
- middlewares << [middleware_args, block]
116
+ def middlewares
117
+ @middlewares ||= self.class.middlewares
96
118
  end
97
119
 
98
- def middlewares
99
- @middlewares ||= Web.middlewares.dup
120
+ def use(*args, &block)
121
+ middlewares << [args, block]
100
122
  end
101
123
 
102
124
  def call(env)
125
+ env[:csp_nonce] = SecureRandom.base64(16)
103
126
  app.call(env)
104
127
  end
105
128
 
@@ -113,81 +136,80 @@ module Sidekiq
113
136
  end
114
137
 
115
138
  def enable(*opts)
116
- opts.each {|key| set(key, true) }
139
+ opts.each { |key| set(key, true) }
117
140
  end
118
141
 
119
142
  def disable(*opts)
120
- opts.each {|key| set(key, false) }
143
+ opts.each { |key| set(key, false) }
121
144
  end
122
145
 
123
146
  def set(attribute, value)
124
147
  send(:"#{attribute}=", value)
125
148
  end
126
149
 
127
- # Default values
128
- set :sessions, true
129
-
130
- attr_writer :sessions
131
-
132
- def sessions
133
- unless instance_variable_defined?("@sessions")
134
- @sessions = self.class.sessions
135
- @sessions = @sessions.to_hash.dup if @sessions.respond_to?(:to_hash)
150
+ # Register a class as a Sidekiq Web UI extension. The class should
151
+ # provide one or more tabs which map to an index route. Options:
152
+ #
153
+ # @param extension [Class] Class which contains the HTTP actions, required
154
+ # @param name [String] the name of the extension, used to namespace assets
155
+ # @param tab [String | Array] labels(s) of the UI tabs
156
+ # @param index [String | Array] index route(s) for each tab
157
+ # @param root_dir [String] directory location to find assets, locales and views, typically `web/` within the gemfile
158
+ # @param asset_paths [Array] one or more directories under {root}/assets/{name} to be publicly served, e.g. ["js", "css", "img"]
159
+ # @param cache_for [Integer] amount of time to cache assets, default one day
160
+ #
161
+ # TODO name, tab and index will be mandatory in 8.0
162
+ #
163
+ # Web extensions will have a root `web/` directory with `locales/`, `assets/`
164
+ # and `views/` subdirectories.
165
+ def self.register(extension, name: nil, tab: nil, index: nil, root_dir: nil, cache_for: 86400, asset_paths: nil)
166
+ tab = Array(tab)
167
+ index = Array(index)
168
+ tab.zip(index).each do |tab, index|
169
+ tabs[tab] = index
170
+ end
171
+ if root_dir
172
+ locdir = File.join(root_dir, "locales")
173
+ locales << locdir if File.directory?(locdir)
174
+
175
+ if asset_paths && name
176
+ # if you have {root}/assets/{name}/js/scripts.js
177
+ # and {root}/assets/{name}/css/styles.css
178
+ # you would pass in:
179
+ # asset_paths: ["js", "css"]
180
+ # See script_tag and style_tag in web/helpers.rb
181
+ assdir = File.join(root_dir, "assets")
182
+ assurls = Array(asset_paths).map { |x| "/#{name}/#{x}" }
183
+ assetprops = {
184
+ urls: assurls,
185
+ root: assdir,
186
+ cascade: true
187
+ }
188
+ assetprops[:header_rules] = [[:all, {Rack::CACHE_CONTROL => "private, max-age=#{cache_for.to_i}"}]] if cache_for
189
+ middlewares << [[Rack::Static, assetprops], nil]
190
+ end
136
191
  end
137
192
 
138
- @sessions
139
- end
140
-
141
- def self.register(extension)
193
+ yield self if block_given?
142
194
  extension.registered(WebApplication)
143
195
  end
144
196
 
145
197
  private
146
198
 
147
- def using?(middleware)
148
- middlewares.any? do |(m,_)|
149
- m.kind_of?(Array) && (m[0] == middleware || m[0].kind_of?(middleware))
150
- end
151
- end
152
-
153
- def build_sessions
154
- middlewares = self.middlewares
155
-
156
- unless using?(::Rack::Protection) || ENV['RACK_ENV'] == 'test'
157
- middlewares.unshift [[::Rack::Protection, { use: :authenticity_token }], nil]
158
- end
159
-
160
- s = sessions
161
- return unless s
162
-
163
- unless using? ::Rack::Session::Cookie
164
- unless secret = Web.session_secret
165
- require 'securerandom'
166
- secret = SecureRandom.hex(64)
167
- end
168
-
169
- options = { secret: secret }
170
- options = options.merge(s.to_hash) if s.respond_to? :to_hash
171
-
172
- middlewares.unshift [[::Rack::Session::Cookie, options], nil]
173
- end
174
- end
175
-
176
199
  def build
177
- build_sessions
178
-
179
- middlewares = self.middlewares
180
200
  klass = self.class
201
+ m = middlewares
181
202
 
182
- ::Rack::Builder.new do
183
- %w(stylesheets javascripts images).each do |asset_dir|
184
- map "/#{asset_dir}" do
185
- run ::Rack::File.new("#{ASSETS}/#{asset_dir}", { 'Cache-Control' => 'public, max-age=86400' })
186
- end
187
- end
188
-
189
- middlewares.each {|middleware, block| use(*middleware, &block) }
203
+ rules = []
204
+ rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
190
205
 
206
+ ::Rack::Builder.new do
207
+ use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
208
+ root: ASSETS,
209
+ cascade: true,
210
+ header_rules: rules
211
+ m.each { |middleware, block| use(*middleware, &block) }
212
+ use Sidekiq::Web::CsrfProtection unless $TESTING
191
213
  run WebApplication.new(klass)
192
214
  end
193
215
  end
@@ -196,18 +218,9 @@ module Sidekiq
196
218
  Sidekiq::WebApplication.helpers WebHelpers
197
219
  Sidekiq::WebApplication.helpers Sidekiq::Paginator
198
220
 
199
- Sidekiq::WebAction.class_eval "def _render\n#{ERB.new(File.read(Web::LAYOUT)).src}\nend"
200
- end
201
-
202
- if defined?(::ActionDispatch::Request::Session) &&
203
- !::ActionDispatch::Request::Session.method_defined?(:each)
204
- # mperham/sidekiq#2460
205
- # Rack apps can't reuse the Rails session store without
206
- # this monkeypatch, fixed in Rails 5.
207
- class ActionDispatch::Request::Session
208
- def each(&block)
209
- hash = self.to_hash
210
- hash.each(&block)
221
+ Sidekiq::WebAction.class_eval <<-RUBY, Web::LAYOUT, -1 # standard:disable Style/EvalWithLocation
222
+ def _render
223
+ #{ERB.new(File.read(Web::LAYOUT)).src}
211
224
  end
212
- end
225
+ RUBY
213
226
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ # Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
5
+ # Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
6
+ #
7
+ # The term "worker" is too generic and overly confusing, used in several
8
+ # different contexts meaning different things. Many people call a Sidekiq
9
+ # process a "worker". Some people call the thread that executes jobs a
10
+ # "worker". This change brings Sidekiq closer to ActiveJob where your job
11
+ # classes extend ApplicationJob.
12
+ Worker = Job
13
+ end
data/lib/sidekiq.rb CHANGED
@@ -1,237 +1,149 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
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'
5
2
 
6
- require 'sidekiq/logging'
7
- require 'sidekiq/client'
8
- require 'sidekiq/worker'
9
- require 'sidekiq/redis_connection'
3
+ require "sidekiq/version"
4
+ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.7.0." if RUBY_PLATFORM != "java" && Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7.0")
10
5
 
11
- require 'json'
6
+ begin
7
+ require "sidekiq-ent/version"
8
+ fail <<~EOM if Gem::Version.new(Sidekiq::Enterprise::VERSION).segments[0] != Sidekiq::MAJOR
12
9
 
13
- module Sidekiq
14
- NAME = 'Sidekiq'
15
- LICENSE = 'See LICENSE and the LGPL-3.0 for licensing details.'
16
-
17
- DEFAULTS = {
18
- queues: [],
19
- labels: [],
20
- concurrency: 25,
21
- require: '.',
22
- environment: nil,
23
- timeout: 8,
24
- poll_interval_average: nil,
25
- average_scheduled_poll_interval: 15,
26
- error_handlers: [],
27
- lifecycle_events: {
28
- startup: [],
29
- quiet: [],
30
- shutdown: [],
31
- heartbeat: [],
32
- },
33
- dead_max_jobs: 10_000,
34
- dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
35
- reloader: proc { |&block| block.call },
36
- executor: proc { |&block| block.call },
37
- }
38
-
39
- DEFAULT_WORKER_OPTIONS = {
40
- 'retry' => true,
41
- 'queue' => 'default'
42
- }
43
-
44
- FAKE_INFO = {
45
- "redis_version" => "9.9.9",
46
- "uptime_in_days" => "9999",
47
- "connected_clients" => "9999",
48
- "used_memory_human" => "9P",
49
- "used_memory_peak_human" => "9P"
50
- }.freeze
10
+ Sidekiq Enterprise #{Sidekiq::Enterprise::VERSION} does not work with Sidekiq #{Sidekiq::VERSION}.
11
+ Starting with Sidekiq 7, major versions are synchronized so Sidekiq Enterprise 7 works with Sidekiq 7.
12
+ Use `bundle up sidekiq-ent` to upgrade.
51
13
 
52
- def self.❨╯°□°❩╯︵┻━┻
53
- puts "Calm down, yo."
54
- end
14
+ EOM
15
+ rescue LoadError
16
+ end
55
17
 
56
- def self.options
57
- @options ||= DEFAULTS.dup
58
- end
59
- def self.options=(opts)
60
- @options = opts
61
- end
18
+ begin
19
+ require "sidekiq/pro/version"
20
+ fail <<~EOM if Gem::Version.new(Sidekiq::Pro::VERSION).segments[0] != Sidekiq::MAJOR
62
21
 
63
- ##
64
- # Configuration for Sidekiq server, use like:
65
- #
66
- # Sidekiq.configure_server do |config|
67
- # config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
68
- # config.server_middleware do |chain|
69
- # chain.add MyServerHook
70
- # end
71
- # end
72
- def self.configure_server
73
- yield self if server?
74
- end
22
+ Sidekiq Pro #{Sidekiq::Pro::VERSION} does not work with Sidekiq #{Sidekiq::VERSION}.
23
+ Starting with Sidekiq 7, major versions are synchronized so Sidekiq Pro 7 works with Sidekiq 7.
24
+ Use `bundle up sidekiq-pro` to upgrade.
75
25
 
76
- ##
77
- # Configuration for Sidekiq client, use like:
78
- #
79
- # Sidekiq.configure_client do |config|
80
- # config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
81
- # end
82
- def self.configure_client
83
- yield self unless server?
26
+ EOM
27
+ rescue LoadError
28
+ end
29
+
30
+ require "sidekiq/config"
31
+ require "sidekiq/logger"
32
+ require "sidekiq/client"
33
+ require "sidekiq/transaction_aware_client"
34
+ require "sidekiq/job"
35
+ require "sidekiq/iterable_job"
36
+ require "sidekiq/worker_compatibility_alias"
37
+ require "sidekiq/redis_client_adapter"
38
+
39
+ require "json"
40
+
41
+ module Sidekiq
42
+ NAME = "Sidekiq"
43
+ LICENSE = "See LICENSE and the LGPL-3.0 for licensing details."
44
+
45
+ def self.❨╯°□°❩╯︵┻━┻
46
+ puts "Take a deep breath and count to ten..."
84
47
  end
85
48
 
86
49
  def self.server?
87
50
  defined?(Sidekiq::CLI)
88
51
  end
89
52
 
90
- def self.redis
91
- raise ArgumentError, "requires a block" unless block_given?
92
- redis_pool.with do |conn|
93
- retryable = true
94
- begin
95
- yield conn
96
- rescue Redis::CommandError => ex
97
- #2550 Failover can cause the server to become a slave, need
98
- # to disconnect and reopen the socket to get back to the master.
99
- (conn.disconnect!; retryable = false; retry) if retryable && ex.message =~ /READONLY/
100
- raise
101
- end
102
- end
103
- end
104
-
105
- def self.redis_info
106
- redis do |conn|
107
- begin
108
- # admin commands can't go through redis-namespace starting
109
- # in redis-namespace 2.0
110
- if conn.respond_to?(:namespace)
111
- conn.redis.info
112
- else
113
- conn.info
114
- end
115
- rescue Redis::CommandError => ex
116
- #2850 return fake version when INFO command has (probably) been renamed
117
- raise unless ex.message =~ /unknown command/
118
- FAKE_INFO
119
- end
120
- end
53
+ def self.load_json(string)
54
+ JSON.parse(string)
121
55
  end
122
56
 
123
- def self.redis_pool
124
- @redis ||= Sidekiq::RedisConnection.create
57
+ def self.dump_json(object)
58
+ JSON.generate(object)
125
59
  end
126
60
 
127
- def self.redis=(hash)
128
- @redis = if hash.is_a?(ConnectionPool)
129
- hash
130
- else
131
- Sidekiq::RedisConnection.create(hash)
132
- end
61
+ def self.pro?
62
+ defined?(Sidekiq::Pro)
133
63
  end
134
64
 
135
- def self.client_middleware
136
- @client_chain ||= Middleware::Chain.new
137
- yield @client_chain if block_given?
138
- @client_chain
65
+ def self.ent?
66
+ defined?(Sidekiq::Enterprise)
139
67
  end
140
68
 
141
- def self.server_middleware
142
- @server_chain ||= default_server_middleware
143
- yield @server_chain if block_given?
144
- @server_chain
69
+ def self.redis_pool
70
+ (Thread.current[:sidekiq_capsule] || default_configuration).redis_pool
145
71
  end
146
72
 
147
- def self.default_server_middleware
148
- require 'sidekiq/middleware/server/retry_jobs'
149
- require 'sidekiq/middleware/server/logging'
150
-
151
- Middleware::Chain.new do |m|
152
- m.add Middleware::Server::RetryJobs
153
- m.add Middleware::Server::Logging
154
- end
73
+ def self.redis(&block)
74
+ (Thread.current[:sidekiq_capsule] || default_configuration).redis(&block)
155
75
  end
156
76
 
157
- def self.default_worker_options=(hash)
158
- @default_worker_options = default_worker_options.merge(hash.stringify_keys)
159
- end
160
- def self.default_worker_options
161
- defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
77
+ def self.strict_args!(mode = :raise)
78
+ Sidekiq::Config::DEFAULTS[:on_complex_arguments] = mode
162
79
  end
163
80
 
164
- # Sidekiq.configure_server do |config|
165
- # config.default_retries_exhausted = -> (job, ex) do
166
- # end
167
- # end
168
- def self.default_retries_exhausted=(prok)
169
- @default_retries_exhausted = prok
170
- end
171
- @default_retries_exhausted = ->(job, ex) { }
172
- def self.default_retries_exhausted
173
- @default_retries_exhausted
81
+ def self.default_job_options=(hash)
82
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
174
83
  end
175
84
 
176
- def self.load_json(string)
177
- JSON.parse(string)
85
+ def self.default_job_options
86
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
178
87
  end
179
- def self.dump_json(object)
180
- JSON.generate(object)
88
+
89
+ def self.default_configuration
90
+ @config ||= Sidekiq::Config.new
181
91
  end
182
92
 
183
93
  def self.logger
184
- Sidekiq::Logging.logger
94
+ default_configuration.logger
185
95
  end
186
- def self.logger=(log)
187
- Sidekiq::Logging.logger = log
96
+
97
+ def self.configure_server(&block)
98
+ (@config_blocks ||= []) << block
99
+ yield default_configuration if server?
188
100
  end
189
101
 
190
- # How frequently Redis should be checked by a random Sidekiq process for
191
- # scheduled and retriable jobs. Each individual process will take turns by
192
- # waiting some multiple of this value.
193
- #
194
- # See sidekiq/scheduled.rb for an in-depth explanation of this value
195
- def self.average_scheduled_poll_interval=(interval)
196
- self.options[:average_scheduled_poll_interval] = interval
102
+ def self.freeze!
103
+ @frozen = true
104
+ @config_blocks = nil
105
+ default_configuration.freeze!
197
106
  end
198
107
 
199
- # Register a proc to handle any error which occurs within the Sidekiq process.
108
+ # Creates a Sidekiq::Config instance that is more tuned for embedding
109
+ # within an arbitrary Ruby process. Notably it reduces concurrency by
110
+ # default so there is less contention for CPU time with other threads.
200
111
  #
201
- # Sidekiq.configure_server do |config|
202
- # config.error_handlers << proc {|ex,ctx_hash| MyErrorService.notify(ex, ctx_hash) }
112
+ # instance = Sidekiq.configure_embed do |config|
113
+ # config.queues = %w[critical default low]
203
114
  # end
115
+ # instance.run
116
+ # sleep 10
117
+ # instance.stop
204
118
  #
205
- # The default error handler logs errors to Sidekiq.logger.
206
- def self.error_handlers
207
- self.options[:error_handlers]
119
+ # NB: it is really easy to overload a Ruby process with threads due to the GIL.
120
+ # I do not recommend setting concurrency higher than 2-3.
121
+ #
122
+ # NB: Sidekiq only supports one instance in memory. You will get undefined behavior
123
+ # if you try to embed Sidekiq twice in the same process.
124
+ def self.configure_embed(&block)
125
+ raise "Sidekiq global configuration is frozen, you must create all embedded instances BEFORE calling `run`" if @frozen
126
+
127
+ require "sidekiq/embedded"
128
+ cfg = default_configuration
129
+ cfg.concurrency = 2
130
+ @config_blocks&.each { |block| block.call(cfg) }
131
+ yield cfg
132
+
133
+ Sidekiq::Embedded.new(cfg)
208
134
  end
209
135
 
210
- # Register a block to run at a point in the Sidekiq lifecycle.
211
- # :startup, :quiet or :shutdown are valid events.
212
- #
213
- # Sidekiq.configure_server do |config|
214
- # config.on(:shutdown) do
215
- # puts "Goodbye cruel world!"
216
- # end
217
- # end
218
- def self.on(event, &block)
219
- raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
220
- raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
221
- options[:lifecycle_events][event] << block
136
+ def self.configure_client
137
+ yield default_configuration unless server?
222
138
  end
223
139
 
224
- # We are shutting down Sidekiq but what about workers that
140
+ # We are shutting down Sidekiq but what about threads that
225
141
  # are working on some long job? This error is
226
- # raised in workers that have not finished within the hard
142
+ # raised in jobs that have not finished within the hard
227
143
  # timeout limit. This is needed to rollback db transactions,
228
144
  # otherwise Ruby's Thread#kill will commit. See #377.
229
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
145
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
230
146
  class Shutdown < Interrupt; end
231
-
232
147
  end
233
148
 
234
- require 'sidekiq/extensions/class_methods'
235
- require 'sidekiq/extensions/action_mailer'
236
- require 'sidekiq/extensions/active_record'
237
- require 'sidekiq/rails' if defined?(::Rails::Engine)
149
+ require "sidekiq/rails" if defined?(::Rails::Engine)