sidekiq 4.2.10 → 7.3.2

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 (158) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +859 -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 +212 -119
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/generators/sidekiq/job_generator.rb +59 -0
  10. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  11. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  12. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  13. data/lib/sidekiq/api.rb +680 -315
  14. data/lib/sidekiq/capsule.rb +132 -0
  15. data/lib/sidekiq/cli.rb +268 -248
  16. data/lib/sidekiq/client.rb +136 -101
  17. data/lib/sidekiq/component.rb +68 -0
  18. data/lib/sidekiq/config.rb +293 -0
  19. data/lib/sidekiq/deploy.rb +64 -0
  20. data/lib/sidekiq/embedded.rb +63 -0
  21. data/lib/sidekiq/fetch.rb +49 -42
  22. data/lib/sidekiq/iterable_job.rb +55 -0
  23. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  24. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  25. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  26. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  27. data/lib/sidekiq/job/iterable.rb +231 -0
  28. data/lib/sidekiq/job.rb +385 -0
  29. data/lib/sidekiq/job_logger.rb +62 -0
  30. data/lib/sidekiq/job_retry.rb +305 -0
  31. data/lib/sidekiq/job_util.rb +109 -0
  32. data/lib/sidekiq/launcher.rb +208 -108
  33. data/lib/sidekiq/logger.rb +131 -0
  34. data/lib/sidekiq/manager.rb +43 -47
  35. data/lib/sidekiq/metrics/query.rb +158 -0
  36. data/lib/sidekiq/metrics/shared.rb +97 -0
  37. data/lib/sidekiq/metrics/tracking.rb +148 -0
  38. data/lib/sidekiq/middleware/chain.rb +113 -56
  39. data/lib/sidekiq/middleware/current_attributes.rb +113 -0
  40. data/lib/sidekiq/middleware/i18n.rb +7 -7
  41. data/lib/sidekiq/middleware/modules.rb +23 -0
  42. data/lib/sidekiq/monitor.rb +147 -0
  43. data/lib/sidekiq/paginator.rb +28 -16
  44. data/lib/sidekiq/processor.rb +188 -98
  45. data/lib/sidekiq/rails.rb +46 -97
  46. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  47. data/lib/sidekiq/redis_connection.rb +71 -73
  48. data/lib/sidekiq/ring_buffer.rb +31 -0
  49. data/lib/sidekiq/scheduled.rb +140 -51
  50. data/lib/sidekiq/sd_notify.rb +149 -0
  51. data/lib/sidekiq/systemd.rb +26 -0
  52. data/lib/sidekiq/testing/inline.rb +6 -5
  53. data/lib/sidekiq/testing.rb +95 -85
  54. data/lib/sidekiq/transaction_aware_client.rb +51 -0
  55. data/lib/sidekiq/version.rb +3 -1
  56. data/lib/sidekiq/web/action.rb +22 -16
  57. data/lib/sidekiq/web/application.rb +230 -86
  58. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  59. data/lib/sidekiq/web/helpers.rb +241 -104
  60. data/lib/sidekiq/web/router.rb +23 -19
  61. data/lib/sidekiq/web.rb +118 -110
  62. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  63. data/lib/sidekiq.rb +96 -185
  64. data/sidekiq.gemspec +26 -27
  65. data/web/assets/images/apple-touch-icon.png +0 -0
  66. data/web/assets/javascripts/application.js +157 -61
  67. data/web/assets/javascripts/base-charts.js +106 -0
  68. data/web/assets/javascripts/chart.min.js +13 -0
  69. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  70. data/web/assets/javascripts/dashboard-charts.js +192 -0
  71. data/web/assets/javascripts/dashboard.js +37 -280
  72. data/web/assets/javascripts/metrics.js +298 -0
  73. data/web/assets/stylesheets/application-dark.css +147 -0
  74. data/web/assets/stylesheets/application-rtl.css +163 -0
  75. data/web/assets/stylesheets/application.css +173 -198
  76. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  77. data/web/assets/stylesheets/bootstrap.css +2 -2
  78. data/web/locales/ar.yml +87 -0
  79. data/web/locales/cs.yml +62 -62
  80. data/web/locales/da.yml +60 -53
  81. data/web/locales/de.yml +65 -53
  82. data/web/locales/el.yml +43 -24
  83. data/web/locales/en.yml +86 -64
  84. data/web/locales/es.yml +70 -53
  85. data/web/locales/fa.yml +65 -64
  86. data/web/locales/fr.yml +83 -62
  87. data/web/locales/gd.yml +99 -0
  88. data/web/locales/he.yml +80 -0
  89. data/web/locales/hi.yml +59 -59
  90. data/web/locales/it.yml +53 -53
  91. data/web/locales/ja.yml +75 -62
  92. data/web/locales/ko.yml +52 -52
  93. data/web/locales/lt.yml +83 -0
  94. data/web/locales/nb.yml +61 -61
  95. data/web/locales/nl.yml +52 -52
  96. data/web/locales/pl.yml +45 -45
  97. data/web/locales/pt-br.yml +83 -55
  98. data/web/locales/pt.yml +51 -51
  99. data/web/locales/ru.yml +68 -63
  100. data/web/locales/sv.yml +53 -53
  101. data/web/locales/ta.yml +60 -60
  102. data/web/locales/tr.yml +101 -0
  103. data/web/locales/uk.yml +62 -61
  104. data/web/locales/ur.yml +80 -0
  105. data/web/locales/vi.yml +83 -0
  106. data/web/locales/zh-cn.yml +43 -16
  107. data/web/locales/zh-tw.yml +42 -8
  108. data/web/views/_footer.erb +21 -3
  109. data/web/views/_job_info.erb +21 -4
  110. data/web/views/_metrics_period_select.erb +12 -0
  111. data/web/views/_nav.erb +5 -19
  112. data/web/views/_paging.erb +3 -1
  113. data/web/views/_poll_link.erb +3 -6
  114. data/web/views/_summary.erb +7 -7
  115. data/web/views/busy.erb +85 -31
  116. data/web/views/dashboard.erb +50 -20
  117. data/web/views/dead.erb +3 -3
  118. data/web/views/filtering.erb +7 -0
  119. data/web/views/layout.erb +17 -6
  120. data/web/views/metrics.erb +91 -0
  121. data/web/views/metrics_for_job.erb +59 -0
  122. data/web/views/morgue.erb +14 -15
  123. data/web/views/queue.erb +34 -24
  124. data/web/views/queues.erb +20 -4
  125. data/web/views/retries.erb +19 -16
  126. data/web/views/retry.erb +3 -3
  127. data/web/views/scheduled.erb +19 -17
  128. metadata +91 -198
  129. data/.github/contributing.md +0 -32
  130. data/.github/issue_template.md +0 -9
  131. data/.gitignore +0 -12
  132. data/.travis.yml +0 -18
  133. data/3.0-Upgrade.md +0 -70
  134. data/4.0-Upgrade.md +0 -53
  135. data/COMM-LICENSE +0 -95
  136. data/Ent-Changes.md +0 -173
  137. data/Gemfile +0 -29
  138. data/LICENSE +0 -9
  139. data/Pro-2.0-Upgrade.md +0 -138
  140. data/Pro-3.0-Upgrade.md +0 -44
  141. data/Pro-Changes.md +0 -628
  142. data/Rakefile +0 -12
  143. data/bin/sidekiqctl +0 -99
  144. data/code_of_conduct.md +0 -50
  145. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  146. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  147. data/lib/sidekiq/core_ext.rb +0 -119
  148. data/lib/sidekiq/exception_handler.rb +0 -31
  149. data/lib/sidekiq/extensions/action_mailer.rb +0 -57
  150. data/lib/sidekiq/extensions/active_record.rb +0 -40
  151. data/lib/sidekiq/extensions/class_methods.rb +0 -40
  152. data/lib/sidekiq/extensions/generic_proxy.rb +0 -25
  153. data/lib/sidekiq/logging.rb +0 -106
  154. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  155. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  156. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  157. data/lib/sidekiq/util.rb +0 -63
  158. data/lib/sidekiq/worker.rb +0 -121
data/lib/sidekiq/web.rb CHANGED
@@ -1,51 +1,59 @@
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
 
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
51
+
36
52
  class << self
37
53
  def settings
38
54
  self
39
55
  end
40
56
 
41
- def middlewares
42
- @middlewares ||= []
43
- end
44
-
45
- def use(*middleware_args, &block)
46
- middlewares << [middleware_args, block]
47
- end
48
-
49
57
  def default_tabs
50
58
  DEFAULT_TABS
51
59
  end
@@ -55,6 +63,10 @@ module Sidekiq
55
63
  end
56
64
  alias_method :tabs, :custom_tabs
57
65
 
66
+ def custom_job_info_rows
67
+ @custom_job_info_rows ||= []
68
+ end
69
+
58
70
  def locales
59
71
  @locales ||= LOCALES
60
72
  end
@@ -64,42 +76,48 @@ module Sidekiq
64
76
  end
65
77
 
66
78
  def enable(*opts)
67
- opts.each {|key| set(key, true) }
79
+ opts.each { |key| set(key, true) }
68
80
  end
69
81
 
70
82
  def disable(*opts)
71
- opts.each {|key| set(key, false) }
83
+ opts.each { |key| set(key, false) }
84
+ end
85
+
86
+ def middlewares
87
+ @middlewares ||= []
88
+ end
89
+
90
+ def use(*args, &block)
91
+ middlewares << [args, block]
72
92
  end
73
93
 
74
- # Helper for the Sinatra syntax: Sidekiq::Web.set(:session_secret, Rails.application.secrets...)
75
94
  def set(attribute, value)
76
95
  send(:"#{attribute}=", value)
77
96
  end
78
97
 
79
- attr_accessor :app_url, :session_secret, :redis_pool, :sessions
98
+ attr_accessor :app_url, :redis_pool
80
99
  attr_writer :locales, :views
81
100
  end
82
101
 
83
102
  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
103
+ child.app_url = app_url
104
+ child.redis_pool = redis_pool
88
105
  end
89
106
 
90
107
  def settings
91
108
  self.class.settings
92
109
  end
93
110
 
94
- def use(*middleware_args, &block)
95
- middlewares << [middleware_args, block]
111
+ def middlewares
112
+ @middlewares ||= self.class.middlewares
96
113
  end
97
114
 
98
- def middlewares
99
- @middlewares ||= Web.middlewares.dup
115
+ def use(*args, &block)
116
+ middlewares << [args, block]
100
117
  end
101
118
 
102
119
  def call(env)
120
+ env[:csp_nonce] = SecureRandom.base64(16)
103
121
  app.call(env)
104
122
  end
105
123
 
@@ -113,81 +131,80 @@ module Sidekiq
113
131
  end
114
132
 
115
133
  def enable(*opts)
116
- opts.each {|key| set(key, true) }
134
+ opts.each { |key| set(key, true) }
117
135
  end
118
136
 
119
137
  def disable(*opts)
120
- opts.each {|key| set(key, false) }
138
+ opts.each { |key| set(key, false) }
121
139
  end
122
140
 
123
141
  def set(attribute, value)
124
142
  send(:"#{attribute}=", value)
125
143
  end
126
144
 
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)
145
+ # Register a class as a Sidekiq Web UI extension. The class should
146
+ # provide one or more tabs which map to an index route. Options:
147
+ #
148
+ # @param extension [Class] Class which contains the HTTP actions, required
149
+ # @param name [String] the name of the extension, used to namespace assets
150
+ # @param tab [String | Array] labels(s) of the UI tabs
151
+ # @param index [String | Array] index route(s) for each tab
152
+ # @param root_dir [String] directory location to find assets, locales and views, typically `web/` within the gemfile
153
+ # @param asset_paths [Array] one or more directories under {root}/assets/{name} to be publicly served, e.g. ["js", "css", "img"]
154
+ # @param cache_for [Integer] amount of time to cache assets, default one day
155
+ #
156
+ # TODO name, tab and index will be mandatory in 8.0
157
+ #
158
+ # Web extensions will have a root `web/` directory with `locales/`, `assets/`
159
+ # and `views/` subdirectories.
160
+ def self.register(extension, name: nil, tab: nil, index: nil, root_dir: nil, cache_for: 86400, asset_paths: nil)
161
+ tab = Array(tab)
162
+ index = Array(index)
163
+ tab.zip(index).each do |tab, index|
164
+ tabs[tab] = index
165
+ end
166
+ if root_dir
167
+ locdir = File.join(root_dir, "locales")
168
+ locales << locdir if File.directory?(locdir)
169
+
170
+ if asset_paths && name
171
+ # if you have {root}/assets/{name}/js/scripts.js
172
+ # and {root}/assets/{name}/css/styles.css
173
+ # you would pass in:
174
+ # asset_paths: ["js", "css"]
175
+ # See script_tag and style_tag in web/helpers.rb
176
+ assdir = File.join(root_dir, "assets")
177
+ assurls = Array(asset_paths).map { |x| "/#{name}/#{x}" }
178
+ assetprops = {
179
+ urls: assurls,
180
+ root: assdir,
181
+ cascade: true
182
+ }
183
+ assetprops[:header_rules] = [[:all, {Rack::CACHE_CONTROL => "private, max-age=#{cache_for.to_i}"}]] if cache_for
184
+ middlewares << [[Rack::Static, assetprops], nil]
185
+ end
136
186
  end
137
187
 
138
- @sessions
139
- end
140
-
141
- def self.register(extension)
188
+ yield self if block_given?
142
189
  extension.registered(WebApplication)
143
190
  end
144
191
 
145
192
  private
146
193
 
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
194
  def build
177
- build_sessions
178
-
179
- middlewares = self.middlewares
180
195
  klass = self.class
196
+ m = middlewares
181
197
 
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) }
198
+ rules = []
199
+ rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
190
200
 
201
+ ::Rack::Builder.new do
202
+ use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
203
+ root: ASSETS,
204
+ cascade: true,
205
+ header_rules: rules
206
+ m.each { |middleware, block| use(*middleware, &block) }
207
+ use Sidekiq::Web::CsrfProtection unless $TESTING
191
208
  run WebApplication.new(klass)
192
209
  end
193
210
  end
@@ -196,18 +213,9 @@ module Sidekiq
196
213
  Sidekiq::WebApplication.helpers WebHelpers
197
214
  Sidekiq::WebApplication.helpers Sidekiq::Paginator
198
215
 
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)
216
+ Sidekiq::WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
217
+ def _render
218
+ #{ERB.new(File.read(Web::LAYOUT)).src}
211
219
  end
212
- end
220
+ RUBY
213
221
  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,148 @@
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
197
105
  end
198
106
 
199
- # Register a proc to handle any error which occurs within the Sidekiq process.
107
+ # Creates a Sidekiq::Config instance that is more tuned for embedding
108
+ # within an arbitrary Ruby process. Notably it reduces concurrency by
109
+ # default so there is less contention for CPU time with other threads.
200
110
  #
201
- # Sidekiq.configure_server do |config|
202
- # config.error_handlers << proc {|ex,ctx_hash| MyErrorService.notify(ex, ctx_hash) }
111
+ # inst = Sidekiq.configure_embed do |config|
112
+ # config.queues = %w[critical default low]
203
113
  # end
114
+ # inst.run
115
+ # sleep 10
116
+ # inst.stop
204
117
  #
205
- # The default error handler logs errors to Sidekiq.logger.
206
- def self.error_handlers
207
- self.options[:error_handlers]
118
+ # NB: it is really easy to overload a Ruby process with threads due to the GIL.
119
+ # I do not recommend setting concurrency higher than 2-3.
120
+ #
121
+ # NB: Sidekiq only supports one instance in memory. You will get undefined behavior
122
+ # if you try to embed Sidekiq twice in the same process.
123
+ def self.configure_embed(&block)
124
+ raise "Sidekiq global configuration is frozen, you must create all embedded instances BEFORE calling `run`" if @frozen
125
+
126
+ require "sidekiq/embedded"
127
+ cfg = default_configuration
128
+ cfg.concurrency = 2
129
+ @config_blocks&.each { |block| block.call(cfg) }
130
+ yield cfg
131
+
132
+ Sidekiq::Embedded.new(cfg)
208
133
  end
209
134
 
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
135
+ def self.configure_client
136
+ yield default_configuration unless server?
222
137
  end
223
138
 
224
- # We are shutting down Sidekiq but what about workers that
139
+ # We are shutting down Sidekiq but what about threads that
225
140
  # are working on some long job? This error is
226
- # raised in workers that have not finished within the hard
141
+ # raised in jobs that have not finished within the hard
227
142
  # timeout limit. This is needed to rollback db transactions,
228
143
  # otherwise Ruby's Thread#kill will commit. See #377.
229
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
144
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
230
145
  class Shutdown < Interrupt; end
231
-
232
146
  end
233
147
 
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)
148
+ require "sidekiq/rails" if defined?(::Rails::Engine)