sidekiq 6.4.0 → 6.4.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.

Potentially problematic release.


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

@@ -82,7 +82,7 @@ module Sidekiq
82
82
  end
83
83
 
84
84
  def get_sidekiq_options # :nodoc:
85
- self.sidekiq_options_hash ||= Sidekiq.default_worker_options
85
+ self.sidekiq_options_hash ||= Sidekiq.default_job_options
86
86
  end
87
87
 
88
88
  def sidekiq_class_attribute(*attrs)
@@ -175,16 +175,18 @@ module Sidekiq
175
175
 
176
176
  def initialize(klass, opts)
177
177
  @klass = klass
178
- @opts = opts
178
+ # NB: the internal hash always has stringified keys
179
+ @opts = opts.transform_keys(&:to_s)
179
180
 
180
181
  # ActiveJob compatibility
181
- interval = @opts.delete(:wait_until) || @opts.delete(:wait)
182
+ interval = @opts.delete("wait_until") || @opts.delete("wait")
182
183
  at(interval) if interval
183
184
  end
184
185
 
185
186
  def set(options)
186
- interval = options.delete(:wait_until) || options.delete(:wait)
187
- @opts.merge!(options)
187
+ hash = options.transform_keys(&:to_s)
188
+ interval = hash.delete("wait_until") || @opts.delete("wait")
189
+ @opts.merge!(hash)
188
190
  at(interval) if interval
189
191
  self
190
192
  end
@@ -200,7 +202,7 @@ module Sidekiq
200
202
  # Explicit inline execution of a job. Returns nil if the job did not
201
203
  # execute, true otherwise.
202
204
  def perform_inline(*args)
203
- raw = @opts.merge("args" => args, "class" => @klass).transform_keys(&:to_s)
205
+ raw = @opts.merge("args" => args, "class" => @klass)
204
206
 
205
207
  # validate and normalize payload
206
208
  item = normalize_item(raw)
@@ -235,9 +237,9 @@ module Sidekiq
235
237
  alias_method :perform_sync, :perform_inline
236
238
 
237
239
  def perform_bulk(args, batch_size: 1_000)
238
- hash = @opts.transform_keys(&:to_s)
240
+ client = @klass.build_client
239
241
  result = args.each_slice(batch_size).flat_map do |slice|
240
- Sidekiq::Client.push_bulk(hash.merge("class" => @klass, "args" => slice))
242
+ client.push_bulk(@opts.merge("class" => @klass, "args" => slice))
241
243
  end
242
244
 
243
245
  result.is_a?(Enumerator::Lazy) ? result.force : result
@@ -291,6 +293,7 @@ module Sidekiq
291
293
  def perform_inline(*args)
292
294
  Setter.new(self, {}).perform_inline(*args)
293
295
  end
296
+ alias_method :perform_sync, :perform_inline
294
297
 
295
298
  ##
296
299
  # Push a large number of jobs to Redis, while limiting the batch of
@@ -312,12 +315,8 @@ module Sidekiq
312
315
  #
313
316
  # SomeWorker.perform_bulk([[1], [2], [3]])
314
317
  #
315
- def perform_bulk(items, batch_size: 1_000)
316
- result = items.each_slice(batch_size).flat_map do |slice|
317
- Sidekiq::Client.push_bulk("class" => self, "args" => slice)
318
- end
319
-
320
- result.is_a?(Enumerator::Lazy) ? result.force : result
318
+ def perform_bulk(*args, **kwargs)
319
+ Setter.new(self, {}).perform_bulk(*args, **kwargs)
321
320
  end
322
321
 
323
322
  # +interval+ must be a timestamp, numeric or something that acts
@@ -354,10 +353,13 @@ module Sidekiq
354
353
  end
355
354
 
356
355
  def client_push(item) # :nodoc:
357
- pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
358
- stringified_item = item.transform_keys(&:to_s)
356
+ raise ArgumentError, "Job payloads should contain no Symbols: #{item}" if item.any? { |k, v| k.is_a?(::Symbol) }
357
+ build_client.push(item)
358
+ end
359
359
 
360
- Sidekiq::Client.new(pool).push(stringified_item)
360
+ def build_client # :nodoc:
361
+ pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
362
+ Sidekiq::Client.new(pool)
361
363
  end
362
364
  end
363
365
  end
data/lib/sidekiq.rb CHANGED
@@ -40,11 +40,6 @@ module Sidekiq
40
40
  reloader: proc { |&block| block.call }
41
41
  }
42
42
 
43
- DEFAULT_WORKER_OPTIONS = {
44
- "retry" => true,
45
- "queue" => "default"
46
- }
47
-
48
43
  FAKE_INFO = {
49
44
  "redis_version" => "9.9.9",
50
45
  "uptime_in_days" => "9999",
@@ -103,6 +98,7 @@ module Sidekiq
103
98
  # to disconnect and reopen the socket to get back to the primary.
104
99
  # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
105
100
  # 4985 Use the same logic when a blocking command is force-unblocked
101
+ # The same retry logic is also used in client.rb
106
102
  if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
107
103
  conn.disconnect!
108
104
  retryable = false
@@ -157,13 +153,20 @@ module Sidekiq
157
153
  Middleware::Chain.new
158
154
  end
159
155
 
160
- def self.default_worker_options=(hash)
161
- # stringify
162
- @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
156
+ def self.default_worker_options=(hash) # deprecated
157
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
158
+ end
159
+
160
+ def self.default_job_options=(hash)
161
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
163
162
  end
164
163
 
165
- def self.default_worker_options
166
- defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
164
+ def self.default_worker_options # deprecated
165
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
166
+ end
167
+
168
+ def self.default_job_options
169
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
167
170
  end
168
171
 
169
172
  ##
@@ -201,12 +204,12 @@ module Sidekiq
201
204
  end
202
205
 
203
206
  def self.logger
204
- @logger ||= Sidekiq::Logger.new($stdout, level: Logger::INFO)
207
+ @logger ||= Sidekiq::Logger.new($stdout, level: :info)
205
208
  end
206
209
 
207
210
  def self.logger=(logger)
208
211
  if logger.nil?
209
- self.logger.level = Logger::FATAL
212
+ self.logger.fatal!
210
213
  return self.logger
211
214
  end
212
215
 
@@ -219,6 +222,10 @@ module Sidekiq
219
222
  defined?(Sidekiq::Pro)
220
223
  end
221
224
 
225
+ def self.ent?
226
+ defined?(Sidekiq::Enterprise)
227
+ end
228
+
222
229
  # How frequently Redis should be checked by a random Sidekiq process for
223
230
  # scheduled and retriable jobs. Each individual process will take turns by
224
231
  # waiting some multiple of this value.
@@ -257,12 +264,12 @@ module Sidekiq
257
264
  options[:on_complex_arguments] = mode
258
265
  end
259
266
 
260
- # We are shutting down Sidekiq but what about workers that
267
+ # We are shutting down Sidekiq but what about threads that
261
268
  # are working on some long job? This error is
262
- # raised in workers that have not finished within the hard
269
+ # raised in jobs that have not finished within the hard
263
270
  # timeout limit. This is needed to rollback db transactions,
264
271
  # otherwise Ruby's Thread#kill will commit. See #377.
265
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
272
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
266
273
  class Shutdown < Interrupt; end
267
274
  end
268
275
 
@@ -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 + "_full");
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
  }
@@ -202,6 +202,7 @@ table .table-checkbox label {
202
202
 
203
203
  .navbar .navbar-brand .status {
204
204
  color: #585454;
205
+ display: inline;
205
206
  }
206
207
 
207
208
 
@@ -9,7 +9,7 @@
9
9
  </li>
10
10
  <li class="busy col-sm-1">
11
11
  <a href="<%= root_path %>busy">
12
- <span id="txtBusy" class="count"><%= number_with_delimiter(workers.size) %></span>
12
+ <span id="txtBusy" class="count"><%= number_with_delimiter(workset.size) %></span>
13
13
  <span class="desc"><%= t('Busy') %></span>
14
14
  </a>
15
15
  </li>
data/web/views/busy.erb CHANGED
@@ -15,7 +15,7 @@
15
15
  <p><%= t('Threads') %></p>
16
16
  </div>
17
17
  <div class="stat">
18
- <h3><%= ws = workers.size; number_with_delimiter(ws) %></h3>
18
+ <h3><%= ws = workset.size; number_with_delimiter(ws) %></h3>
19
19
  <p><%= t('Busy') %></p>
20
20
  </div>
21
21
  <div class="stat">
@@ -48,7 +48,7 @@
48
48
  <thead>
49
49
  <th><%= t('Name') %></th>
50
50
  <th><%= t('Started') %></th>
51
- <th class="col-sm-1"><%= t('RSS') %><a href="https://github.com/mperham/sidekiq/wiki/Memory#rss"><span class="info-circle" title="Click to learn more about RSS">?</span></a></th>
51
+ <th class="col-sm-1"><%= t('RSS') %><a target="blank" href="https://github.com/mperham/sidekiq/wiki/Memory#rss"><span class="info-circle" title="Click to learn more about RSS">?</span></a></th>
52
52
  <th class="col-sm-1"><%= t('Threads') %></th>
53
53
  <th class="col-sm-1"><%= t('Busy') %></th>
54
54
  <th>&nbsp;</th>
@@ -109,7 +109,7 @@
109
109
  <th><%= t('Arguments') %></th>
110
110
  <th><%= t('Started') %></th>
111
111
  </thead>
112
- <% workers.each do |process, thread, msg| %>
112
+ <% workset.each do |process, thread, msg| %>
113
113
  <% job = Sidekiq::JobRecord.new(msg['payload']) %>
114
114
  <tr>
115
115
  <td><%= process %></td>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.4.0
4
+ version: 6.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-20 00:00:00.000000000 Z
11
+ date: 2022-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  requirements: []
196
- rubygems_version: 3.1.4
196
+ rubygems_version: 3.2.32
197
197
  signing_key:
198
198
  specification_version: 4
199
199
  summary: Simple, efficient background processing for Ruby