sidekiq 6.4.1 → 7.0.0

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +107 -5
  3. data/README.md +14 -13
  4. data/bin/sidekiq +3 -8
  5. data/bin/sidekiqload +26 -29
  6. data/lib/sidekiq/api.rb +232 -157
  7. data/lib/sidekiq/capsule.rb +110 -0
  8. data/lib/sidekiq/cli.rb +80 -86
  9. data/lib/sidekiq/client.rb +54 -42
  10. data/lib/sidekiq/component.rb +66 -0
  11. data/lib/sidekiq/config.rb +271 -0
  12. data/lib/sidekiq/deploy.rb +62 -0
  13. data/lib/sidekiq/embedded.rb +61 -0
  14. data/lib/sidekiq/fetch.rb +20 -19
  15. data/lib/sidekiq/job.rb +375 -10
  16. data/lib/sidekiq/job_logger.rb +1 -1
  17. data/lib/sidekiq/job_retry.rb +74 -53
  18. data/lib/sidekiq/job_util.rb +17 -11
  19. data/lib/sidekiq/launcher.rb +63 -69
  20. data/lib/sidekiq/logger.rb +6 -45
  21. data/lib/sidekiq/manager.rb +33 -32
  22. data/lib/sidekiq/metrics/query.rb +153 -0
  23. data/lib/sidekiq/metrics/shared.rb +95 -0
  24. data/lib/sidekiq/metrics/tracking.rb +134 -0
  25. data/lib/sidekiq/middleware/chain.rb +84 -42
  26. data/lib/sidekiq/middleware/current_attributes.rb +18 -17
  27. data/lib/sidekiq/middleware/i18n.rb +6 -4
  28. data/lib/sidekiq/middleware/modules.rb +21 -0
  29. data/lib/sidekiq/monitor.rb +1 -1
  30. data/lib/sidekiq/paginator.rb +10 -2
  31. data/lib/sidekiq/processor.rb +56 -59
  32. data/lib/sidekiq/rails.rb +10 -9
  33. data/lib/sidekiq/redis_client_adapter.rb +118 -0
  34. data/lib/sidekiq/redis_connection.rb +13 -82
  35. data/lib/sidekiq/ring_buffer.rb +29 -0
  36. data/lib/sidekiq/scheduled.rb +65 -37
  37. data/lib/sidekiq/testing/inline.rb +4 -4
  38. data/lib/sidekiq/testing.rb +41 -68
  39. data/lib/sidekiq/transaction_aware_client.rb +44 -0
  40. data/lib/sidekiq/version.rb +2 -1
  41. data/lib/sidekiq/web/action.rb +3 -3
  42. data/lib/sidekiq/web/application.rb +22 -6
  43. data/lib/sidekiq/web/csrf_protection.rb +3 -3
  44. data/lib/sidekiq/web/helpers.rb +21 -19
  45. data/lib/sidekiq/web.rb +3 -14
  46. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  47. data/lib/sidekiq.rb +84 -207
  48. data/sidekiq.gemspec +29 -5
  49. data/web/assets/javascripts/application.js +58 -26
  50. data/web/assets/javascripts/base-charts.js +106 -0
  51. data/web/assets/javascripts/chart.min.js +13 -0
  52. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  53. data/web/assets/javascripts/dashboard-charts.js +166 -0
  54. data/web/assets/javascripts/dashboard.js +3 -240
  55. data/web/assets/javascripts/metrics.js +236 -0
  56. data/web/assets/stylesheets/application-rtl.css +2 -91
  57. data/web/assets/stylesheets/application.css +64 -297
  58. data/web/locales/ar.yml +70 -70
  59. data/web/locales/cs.yml +62 -62
  60. data/web/locales/da.yml +52 -52
  61. data/web/locales/de.yml +65 -65
  62. data/web/locales/el.yml +43 -24
  63. data/web/locales/en.yml +82 -69
  64. data/web/locales/es.yml +68 -68
  65. data/web/locales/fa.yml +65 -65
  66. data/web/locales/fr.yml +67 -67
  67. data/web/locales/he.yml +65 -64
  68. data/web/locales/hi.yml +59 -59
  69. data/web/locales/it.yml +53 -53
  70. data/web/locales/ja.yml +71 -68
  71. data/web/locales/ko.yml +52 -52
  72. data/web/locales/lt.yml +66 -66
  73. data/web/locales/nb.yml +61 -61
  74. data/web/locales/nl.yml +52 -52
  75. data/web/locales/pl.yml +45 -45
  76. data/web/locales/pt-br.yml +63 -55
  77. data/web/locales/pt.yml +51 -51
  78. data/web/locales/ru.yml +67 -66
  79. data/web/locales/sv.yml +53 -53
  80. data/web/locales/ta.yml +60 -60
  81. data/web/locales/uk.yml +62 -61
  82. data/web/locales/ur.yml +64 -64
  83. data/web/locales/vi.yml +67 -67
  84. data/web/locales/zh-cn.yml +37 -11
  85. data/web/locales/zh-tw.yml +42 -8
  86. data/web/views/_footer.erb +5 -2
  87. data/web/views/_nav.erb +1 -1
  88. data/web/views/_summary.erb +1 -1
  89. data/web/views/busy.erb +9 -4
  90. data/web/views/dashboard.erb +36 -4
  91. data/web/views/metrics.erb +80 -0
  92. data/web/views/metrics_for_job.erb +69 -0
  93. data/web/views/queue.erb +5 -1
  94. metadata +69 -22
  95. data/lib/sidekiq/delay.rb +0 -43
  96. data/lib/sidekiq/exception_handler.rb +0 -27
  97. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  98. data/lib/sidekiq/extensions/active_record.rb +0 -43
  99. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  100. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  101. data/lib/sidekiq/util.rb +0 -108
  102. data/lib/sidekiq/worker.rb +0 -362
  103. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -15,7 +15,7 @@ module Sidekiq
15
15
  # so extensions can be localized
16
16
  @strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
17
17
  find_locale_files(lang).each do |file|
18
- strs = YAML.load(File.open(file))
18
+ strs = YAML.safe_load(File.open(file))
19
19
  global.merge!(strs[lang])
20
20
  end
21
21
  end
@@ -140,30 +140,39 @@ module Sidekiq
140
140
  params[:direction] == "asc" ? "↑" : "↓"
141
141
  end
142
142
 
143
- def workers
144
- @workers ||= Sidekiq::Workers.new
143
+ def workset
144
+ @work ||= Sidekiq::WorkSet.new
145
145
  end
146
146
 
147
147
  def processes
148
148
  @processes ||= Sidekiq::ProcessSet.new
149
149
  end
150
150
 
151
+ # Sorts processes by hostname following the natural sort order
152
+ def sorted_processes
153
+ @sorted_processes ||= begin
154
+ return processes unless processes.all? { |p| p["hostname"] }
155
+
156
+ processes.to_a.sort_by do |process|
157
+ # Kudos to `shurikk` on StackOverflow
158
+ # https://stackoverflow.com/a/15170063/575547
159
+ process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a }
160
+ end
161
+ end
162
+ end
163
+
151
164
  def stats
152
165
  @stats ||= Sidekiq::Stats.new
153
166
  end
154
167
 
155
- def redis_connection
168
+ def redis_url
156
169
  Sidekiq.redis do |conn|
157
- conn.connection[:id]
170
+ conn._config.server_url
158
171
  end
159
172
  end
160
173
 
161
- def namespace
162
- @ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
163
- end
164
-
165
174
  def redis_info
166
- Sidekiq.redis_info
175
+ Sidekiq.default_configuration.redis_info
167
176
  end
168
177
 
169
178
  def root_path
@@ -175,7 +184,7 @@ module Sidekiq
175
184
  end
176
185
 
177
186
  def current_status
178
- workers.size == 0 ? "idle" : "active"
187
+ workset.size == 0 ? "idle" : "active"
179
188
  end
180
189
 
181
190
  def relative_time(time)
@@ -301,7 +310,7 @@ module Sidekiq
301
310
  end
302
311
 
303
312
  def environment_title_prefix
304
- environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
313
+ environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
305
314
 
306
315
  "[#{environment.upcase}] " unless environment == "production"
307
316
  end
@@ -314,13 +323,6 @@ module Sidekiq
314
323
  Time.now.utc.strftime("%H:%M:%S UTC")
315
324
  end
316
325
 
317
- def redis_connection_and_namespace
318
- @redis_connection_and_namespace ||= begin
319
- namespace_suffix = namespace.nil? ? "" : "##{namespace}"
320
- "#{redis_connection}#{namespace_suffix}"
321
- end
322
- end
323
-
324
326
  def retry_or_delete_or_kill(job, params)
325
327
  if params["retry"]
326
328
  job.retry
data/lib/sidekiq/web.rb CHANGED
@@ -30,7 +30,8 @@ module Sidekiq
30
30
  "Queues" => "queues",
31
31
  "Retries" => "retries",
32
32
  "Scheduled" => "scheduled",
33
- "Dead" => "morgue"
33
+ "Dead" => "morgue",
34
+ "Metrics" => "metrics"
34
35
  }
35
36
 
36
37
  class << self
@@ -75,14 +76,6 @@ module Sidekiq
75
76
  send(:"#{attribute}=", value)
76
77
  end
77
78
 
78
- def sessions=(val)
79
- puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
80
- end
81
-
82
- def session_secret=(val)
83
- puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
84
- end
85
-
86
79
  attr_accessor :app_url, :redis_pool
87
80
  attr_writer :locales, :views
88
81
  end
@@ -129,10 +122,6 @@ module Sidekiq
129
122
  send(:"#{attribute}=", value)
130
123
  end
131
124
 
132
- def sessions=(val)
133
- puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
134
- end
135
-
136
125
  def self.register(extension)
137
126
  extension.registered(WebApplication)
138
127
  end
@@ -144,7 +133,7 @@ module Sidekiq
144
133
  m = middlewares
145
134
 
146
135
  rules = []
147
- rules = [[:all, {"Cache-Control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
136
+ rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
148
137
 
149
138
  ::Rack::Builder.new do
150
139
  use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
@@ -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,14 +1,39 @@
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.5.0." if RUBY_PLATFORM != "java" && Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5.0")
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")
5
5
 
6
+ begin
7
+ require "sidekiq-ent/version"
8
+ fail <<~EOM if Gem::Version.new(Sidekiq::Enterprise::VERSION).segments[0] != Sidekiq::MAJOR
9
+
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.
13
+
14
+ EOM
15
+ rescue LoadError
16
+ end
17
+
18
+ begin
19
+ require "sidekiq/pro/version"
20
+ fail <<~EOM if Gem::Version.new(Sidekiq::Pro::VERSION).segments[0] != Sidekiq::MAJOR
21
+
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.
25
+
26
+ EOM
27
+ rescue LoadError
28
+ end
29
+
30
+ require "sidekiq/config"
6
31
  require "sidekiq/logger"
7
32
  require "sidekiq/client"
8
- require "sidekiq/worker"
33
+ require "sidekiq/transaction_aware_client"
9
34
  require "sidekiq/job"
10
- require "sidekiq/redis_connection"
11
- require "sidekiq/delay"
35
+ require "sidekiq/worker_compatibility_alias"
36
+ require "sidekiq/redis_client_adapter"
12
37
 
13
38
  require "json"
14
39
 
@@ -16,254 +41,106 @@ module Sidekiq
16
41
  NAME = "Sidekiq"
17
42
  LICENSE = "See LICENSE and the LGPL-3.0 for licensing details."
18
43
 
19
- DEFAULTS = {
20
- queues: [],
21
- labels: [],
22
- concurrency: 10,
23
- require: ".",
24
- strict: true,
25
- environment: nil,
26
- timeout: 25,
27
- poll_interval_average: nil,
28
- average_scheduled_poll_interval: 5,
29
- on_complex_arguments: :warn,
30
- error_handlers: [],
31
- death_handlers: [],
32
- lifecycle_events: {
33
- startup: [],
34
- quiet: [],
35
- shutdown: [],
36
- heartbeat: []
37
- },
38
- dead_max_jobs: 10_000,
39
- dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
40
- reloader: proc { |&block| block.call }
41
- }
42
-
43
- DEFAULT_WORKER_OPTIONS = {
44
- "retry" => true,
45
- "queue" => "default"
46
- }
47
-
48
- FAKE_INFO = {
49
- "redis_version" => "9.9.9",
50
- "uptime_in_days" => "9999",
51
- "connected_clients" => "9999",
52
- "used_memory_human" => "9P",
53
- "used_memory_peak_human" => "9P"
54
- }
55
-
56
44
  def self.❨╯°□°❩╯︵┻━┻
57
- puts "Calm down, yo."
58
- end
59
-
60
- def self.options
61
- @options ||= DEFAULTS.dup
62
- end
63
-
64
- def self.options=(opts)
65
- @options = opts
66
- end
67
-
68
- ##
69
- # Configuration for Sidekiq server, use like:
70
- #
71
- # Sidekiq.configure_server do |config|
72
- # config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
73
- # config.server_middleware do |chain|
74
- # chain.add MyServerHook
75
- # end
76
- # end
77
- def self.configure_server
78
- yield self if server?
79
- end
80
-
81
- ##
82
- # Configuration for Sidekiq client, use like:
83
- #
84
- # Sidekiq.configure_client do |config|
85
- # config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
86
- # end
87
- def self.configure_client
88
- yield self unless server?
45
+ puts "Take a deep breath and count to ten..."
89
46
  end
90
47
 
91
48
  def self.server?
92
49
  defined?(Sidekiq::CLI)
93
50
  end
94
51
 
95
- def self.redis
96
- raise ArgumentError, "requires a block" unless block_given?
97
- redis_pool.with do |conn|
98
- retryable = true
99
- begin
100
- yield conn
101
- rescue Redis::BaseError => ex
102
- # 2550 Failover can cause the server to become a replica, need
103
- # to disconnect and reopen the socket to get back to the primary.
104
- # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
105
- # 4985 Use the same logic when a blocking command is force-unblocked
106
- # The same retry logic is also used in client.rb
107
- if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
108
- conn.disconnect!
109
- retryable = false
110
- retry
111
- end
112
- raise
113
- end
114
- end
115
- end
116
-
117
- def self.redis_info
118
- redis do |conn|
119
- # admin commands can't go through redis-namespace starting
120
- # in redis-namespace 2.0
121
- if conn.respond_to?(:namespace)
122
- conn.redis.info
123
- else
124
- conn.info
125
- end
126
- rescue Redis::CommandError => ex
127
- # 2850 return fake version when INFO command has (probably) been renamed
128
- raise unless /unknown command/.match?(ex.message)
129
- FAKE_INFO
130
- end
131
- end
132
-
133
- def self.redis_pool
134
- @redis ||= Sidekiq::RedisConnection.create
135
- end
136
-
137
- def self.redis=(hash)
138
- @redis = if hash.is_a?(ConnectionPool)
139
- hash
140
- else
141
- Sidekiq::RedisConnection.create(hash)
142
- end
143
- end
144
-
145
- def self.client_middleware
146
- @client_chain ||= Middleware::Chain.new
147
- yield @client_chain if block_given?
148
- @client_chain
52
+ def self.load_json(string)
53
+ JSON.parse(string)
149
54
  end
150
55
 
151
- def self.server_middleware
152
- @server_chain ||= default_server_middleware
153
- yield @server_chain if block_given?
154
- @server_chain
56
+ def self.dump_json(object)
57
+ JSON.generate(object)
155
58
  end
156
59
 
157
- def self.default_server_middleware
158
- Middleware::Chain.new
60
+ def self.pro?
61
+ defined?(Sidekiq::Pro)
159
62
  end
160
63
 
161
- def self.default_worker_options=(hash)
162
- # stringify
163
- @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
64
+ def self.ent?
65
+ defined?(Sidekiq::Enterprise)
164
66
  end
165
67
 
166
- def self.default_worker_options
167
- defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
68
+ def self.redis_pool
69
+ (Thread.current[:sidekiq_capsule] || default_configuration).redis_pool
168
70
  end
169
71
 
170
- ##
171
- # Death handlers are called when all retries for a job have been exhausted and
172
- # the job dies. It's the notification to your application
173
- # that this job will not succeed without manual intervention.
174
- #
175
- # Sidekiq.configure_server do |config|
176
- # config.death_handlers << ->(job, ex) do
177
- # end
178
- # end
179
- def self.death_handlers
180
- options[:death_handlers]
72
+ def self.redis(&block)
73
+ (Thread.current[:sidekiq_capsule] || default_configuration).redis(&block)
181
74
  end
182
75
 
183
- def self.load_json(string)
184
- JSON.parse(string)
76
+ def self.strict_args!(mode = :raise)
77
+ Sidekiq::Config::DEFAULTS[:on_complex_arguments] = mode
185
78
  end
186
79
 
187
- def self.dump_json(object)
188
- JSON.generate(object)
80
+ def self.default_job_options=(hash)
81
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
189
82
  end
190
83
 
191
- def self.log_formatter
192
- @log_formatter ||= if ENV["DYNO"]
193
- Sidekiq::Logger::Formatters::WithoutTimestamp.new
194
- else
195
- Sidekiq::Logger::Formatters::Pretty.new
196
- end
84
+ def self.default_job_options
85
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
197
86
  end
198
87
 
199
- def self.log_formatter=(log_formatter)
200
- @log_formatter = log_formatter
201
- logger.formatter = log_formatter
88
+ def self.default_configuration
89
+ @config ||= Sidekiq::Config.new
202
90
  end
203
91
 
204
92
  def self.logger
205
- @logger ||= Sidekiq::Logger.new($stdout, level: Logger::INFO)
206
- end
207
-
208
- def self.logger=(logger)
209
- if logger.nil?
210
- self.logger.level = Logger::FATAL
211
- return self.logger
212
- end
213
-
214
- logger.extend(Sidekiq::LoggingUtils)
215
-
216
- @logger = logger
93
+ default_configuration.logger
217
94
  end
218
95
 
219
- def self.pro?
220
- defined?(Sidekiq::Pro)
96
+ def self.configure_server(&block)
97
+ (@config_blocks ||= []) << block
98
+ yield default_configuration if server?
221
99
  end
222
100
 
223
- # How frequently Redis should be checked by a random Sidekiq process for
224
- # scheduled and retriable jobs. Each individual process will take turns by
225
- # waiting some multiple of this value.
226
- #
227
- # See sidekiq/scheduled.rb for an in-depth explanation of this value
228
- def self.average_scheduled_poll_interval=(interval)
229
- options[:average_scheduled_poll_interval] = interval
101
+ def self.freeze!
102
+ @frozen = true
103
+ @config_blocks = nil
230
104
  end
231
105
 
232
- # Register a proc to handle any error which occurs within the Sidekiq process.
106
+ # Creates a Sidekiq::Config instance that is more tuned for embedding
107
+ # within an arbitrary Ruby process. Notably it reduces concurrency by
108
+ # default so there is less contention for CPU time with other threads.
233
109
  #
234
- # Sidekiq.configure_server do |config|
235
- # config.error_handlers << proc {|ex,ctx_hash| MyErrorService.notify(ex, ctx_hash) }
110
+ # inst = Sidekiq.configure_embed do |config|
111
+ # config.queues = %w[critical default low]
236
112
  # end
113
+ # inst.run
114
+ # sleep 10
115
+ # inst.terminate
237
116
  #
238
- # The default error handler logs errors to Sidekiq.logger.
239
- def self.error_handlers
240
- options[:error_handlers]
241
- end
242
-
243
- # Register a block to run at a point in the Sidekiq lifecycle.
244
- # :startup, :quiet or :shutdown are valid events.
117
+ # NB: it is really easy to overload a Ruby process with threads due to the GIL.
118
+ # I do not recommend setting concurrency higher than 2-3.
245
119
  #
246
- # Sidekiq.configure_server do |config|
247
- # config.on(:shutdown) do
248
- # puts "Goodbye cruel world!"
249
- # end
250
- # end
251
- def self.on(event, &block)
252
- raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
253
- raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
254
- options[:lifecycle_events][event] << block
120
+ # NB: Sidekiq only supports one instance in memory. You will get undefined behavior
121
+ # if you try to embed Sidekiq twice in the same process.
122
+ def self.configure_embed(&block)
123
+ raise "Sidekiq global configuration is frozen, you must create all embedded instances BEFORE calling `run`" if @frozen
124
+
125
+ require "sidekiq/embedded"
126
+ cfg = default_configuration
127
+ cfg.concurrency = 2
128
+ @config_blocks&.each { |block| block.call(cfg) }
129
+ yield cfg
130
+
131
+ Sidekiq::Embedded.new(cfg)
255
132
  end
256
133
 
257
- def self.strict_args!(mode = :raise)
258
- options[:on_complex_arguments] = mode
134
+ def self.configure_client
135
+ yield default_configuration unless server?
259
136
  end
260
137
 
261
- # We are shutting down Sidekiq but what about workers that
138
+ # We are shutting down Sidekiq but what about threads that
262
139
  # are working on some long job? This error is
263
- # raised in workers that have not finished within the hard
140
+ # raised in jobs that have not finished within the hard
264
141
  # timeout limit. This is needed to rollback db transactions,
265
142
  # otherwise Ruby's Thread#kill will commit. See #377.
266
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
143
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
267
144
  class Shutdown < Interrupt; end
268
145
  end
269
146
 
data/sidekiq.gemspec CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |gem|
9
9
  gem.license = "LGPL-3.0"
10
10
 
11
11
  gem.executables = ["sidekiq", "sidekiqmon"]
12
- gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n")
12
+ gem.files = %w[sidekiq.gemspec README.md Changes.md LICENSE.txt] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n")
13
13
  gem.name = "sidekiq"
14
14
  gem.version = Sidekiq::VERSION
15
- gem.required_ruby_version = ">= 2.5.0"
15
+ gem.required_ruby_version = ">= 2.7.0"
16
16
 
17
17
  gem.metadata = {
18
18
  "homepage_uri" => "https://sidekiq.org",
@@ -22,7 +22,31 @@ Gem::Specification.new do |gem|
22
22
  "source_code_uri" => "https://github.com/mperham/sidekiq"
23
23
  }
24
24
 
25
- gem.add_dependency "redis", ">= 4.2.0"
26
- gem.add_dependency "connection_pool", ">= 2.2.2"
27
- gem.add_dependency "rack", "~> 2.0"
25
+ gem.add_dependency "redis-client", ">= 0.9.0"
26
+ gem.add_dependency "connection_pool", ">= 2.3.0"
27
+ gem.add_dependency "rack", ">= 2.2.4"
28
+ gem.add_dependency "concurrent-ruby", "< 2"
29
+ gem.post_install_message = <<~EOM
30
+
31
+ ####################################################
32
+
33
+
34
+ █████████ █████ ██████████ ██████████ █████ ████ █████ ██████ ██████████ █████
35
+ ███░░░░░███░░███ ░░███░░░░███ ░░███░░░░░█░░███ ███░ ░░███ ███░░░░███ ░███░░░░███ ███░░░███
36
+ ░███ ░░░ ░███ ░███ ░░███ ░███ █ ░ ░███ ███ ░███ ███ ░░███ ░░░ ███ ███ ░░███
37
+ ░░█████████ ░███ ░███ ░███ ░██████ ░███████ ░███ ░███ ░███ ███ ░███ ░███
38
+ ░░░░░░░░███ ░███ ░███ ░███ ░███░░█ ░███░░███ ░███ ░███ ██░███ ███ ░███ ░███
39
+ ███ ░███ ░███ ░███ ███ ░███ ░ █ ░███ ░░███ ░███ ░░███ ░░████ ███ ░░███ ███
40
+ ░░█████████ █████ ██████████ ██████████ █████ ░░████ █████ ░░░██████░██ ███ ██ ░░░█████░
41
+ ░░░░░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░░ ░░ ░░░ ░░ ░░░░░░
42
+
43
+
44
+ WARNING: This is a beta release, expect breakage!
45
+
46
+ 1. Use `gem 'sidekiq', '<7'` in your Gemfile if you don't want to be a beta tester.
47
+ 2. Read the release notes at https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md
48
+ 3. Search for open/closed issues at https://github.com/mperham/sidekiq/issues/
49
+
50
+ ####################################################
51
+ EOM
28
52
  end
@@ -9,7 +9,9 @@ var ready = (callback) => {
9
9
  else document.addEventListener("DOMContentLoaded", callback);
10
10
  }
11
11
 
12
- ready(() => {
12
+ ready(addListeners)
13
+
14
+ function addListeners() {
13
15
  document.querySelectorAll(".check_all").forEach(node => {
14
16
  node.addEventListener("click", event => {
15
17
  node.closest('table').querySelectorAll('input[type=checkbox]').forEach(inp => { inp.checked = !!node.checked; });
@@ -26,42 +28,48 @@ ready(() => {
26
28
  })
27
29
 
28
30
  document.querySelectorAll("[data-toggle]").forEach(node => {
29
- node.addEventListener("click", event => {
30
- var targName = node.getAttribute("data-toggle");
31
- var full = document.getElementById(targName + "_full");
32
- if (full.style.display == "block") {
33
- full.style.display = 'none';
34
- } else {
35
- full.style.display = 'block';
36
- }
37
- })
31
+ node.addEventListener("click", addDataToggleListeners)
38
32
  })
39
33
 
40
34
  updateFuzzyTimes();
35
+ setLivePollFromUrl();
41
36
 
42
37
  var buttons = document.querySelectorAll(".live-poll");
43
38
  if (buttons.length > 0) {
44
39
  buttons.forEach(node => {
45
- node.addEventListener("click", event => {
46
- if (localStorage.sidekiqLivePoll == "enabled") {
47
- localStorage.sidekiqLivePoll = "disabled";
48
- clearTimeout(livePollTimer);
49
- livePollTimer = null;
50
- } else {
51
- localStorage.sidekiqLivePoll = "enabled";
52
- livePollCallback();
53
- }
54
-
55
- updateLivePollButton();
56
- })
40
+ node.addEventListener("click", addPollingListeners)
57
41
  });
58
42
 
59
43
  updateLivePollButton();
60
- if (localStorage.sidekiqLivePoll == "enabled") {
44
+ if (localStorage.sidekiqLivePoll == "enabled" && !livePollTimer) {
61
45
  scheduleLivePoll();
62
46
  }
63
47
  }
64
- })
48
+ }
49
+
50
+ function addPollingListeners(_event) {
51
+ if (localStorage.sidekiqLivePoll == "enabled") {
52
+ localStorage.sidekiqLivePoll = "disabled";
53
+ clearTimeout(livePollTimer);
54
+ livePollTimer = null;
55
+ } else {
56
+ localStorage.sidekiqLivePoll = "enabled";
57
+ livePollCallback();
58
+ }
59
+
60
+ updateLivePollButton();
61
+ }
62
+
63
+ function addDataToggleListeners(event) {
64
+ var source = event.target || event.srcElement;
65
+ var targName = source.getAttribute("data-toggle");
66
+ var full = document.getElementById(targName);
67
+ if (full.style.display == "block") {
68
+ full.style.display = 'none';
69
+ } else {
70
+ full.style.display = 'block';
71
+ }
72
+ }
65
73
 
66
74
  function updateFuzzyTimes() {
67
75
  var locale = document.body.getAttribute("data-locale");
@@ -76,6 +84,14 @@ function updateFuzzyTimes() {
76
84
  t.cancel();
77
85
  }
78
86
 
87
+ function setLivePollFromUrl() {
88
+ var url_params = new URL(window.location.href).searchParams
89
+
90
+ if (url_params.get("poll") == "true") {
91
+ localStorage.sidekiqLivePoll = "enabled";
92
+ }
93
+ }
94
+
79
95
  function updateLivePollButton() {
80
96
  if (localStorage.sidekiqLivePoll == "enabled") {
81
97
  document.querySelectorAll('.live-poll-stop').forEach(box => { box.style.display = "inline-block" })
@@ -89,7 +105,19 @@ function updateLivePollButton() {
89
105
  function livePollCallback() {
90
106
  clearTimeout(livePollTimer);
91
107
 
92
- fetch(window.location.href).then(resp => resp.text()).then(replacePage).finally(scheduleLivePoll)
108
+ fetch(window.location.href)
109
+ .then(checkResponse)
110
+ .then(resp => resp.text())
111
+ .then(replacePage)
112
+ .catch(showError)
113
+ .finally(scheduleLivePoll)
114
+ }
115
+
116
+ function checkResponse(resp) {
117
+ if (!resp.ok) {
118
+ throw response.error();
119
+ }
120
+ return resp
93
121
  }
94
122
 
95
123
  function scheduleLivePoll() {
@@ -107,5 +135,9 @@ function replacePage(text) {
107
135
  var header_status = doc.querySelector('.status')
108
136
  document.querySelector('.status').replaceWith(header_status)
109
137
 
110
- updateFuzzyTimes();
138
+ addListeners();
139
+ }
140
+
141
+ function showError(error) {
142
+ console.error(error)
111
143
  }