sidekiq 6.0.0 → 6.0.7

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +0 -1
  3. data/6.0-Upgrade.md +3 -1
  4. data/Changes.md +131 -1
  5. data/Ent-Changes.md +7 -1
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +106 -94
  8. data/Pro-Changes.md +16 -2
  9. data/README.md +3 -1
  10. data/bin/sidekiq +19 -0
  11. data/bin/sidekiqload +8 -4
  12. data/bin/sidekiqmon +4 -5
  13. data/lib/generators/sidekiq/worker_generator.rb +11 -1
  14. data/lib/sidekiq/api.rb +125 -92
  15. data/lib/sidekiq/cli.rb +33 -20
  16. data/lib/sidekiq/client.rb +20 -4
  17. data/lib/sidekiq/fetch.rb +7 -7
  18. data/lib/sidekiq/job_logger.rb +12 -4
  19. data/lib/sidekiq/job_retry.rb +23 -10
  20. data/lib/sidekiq/launcher.rb +32 -8
  21. data/lib/sidekiq/logger.rb +108 -12
  22. data/lib/sidekiq/middleware/chain.rb +11 -2
  23. data/lib/sidekiq/monitor.rb +3 -18
  24. data/lib/sidekiq/paginator.rb +7 -2
  25. data/lib/sidekiq/processor.rb +18 -20
  26. data/lib/sidekiq/redis_connection.rb +9 -4
  27. data/lib/sidekiq/scheduled.rb +13 -12
  28. data/lib/sidekiq/sd_notify.rb +149 -0
  29. data/lib/sidekiq/systemd.rb +24 -0
  30. data/lib/sidekiq/testing.rb +12 -0
  31. data/lib/sidekiq/util.rb +0 -2
  32. data/lib/sidekiq/version.rb +1 -1
  33. data/lib/sidekiq/web/application.rb +22 -21
  34. data/lib/sidekiq/web/helpers.rb +23 -11
  35. data/lib/sidekiq/web/router.rb +1 -3
  36. data/lib/sidekiq/web.rb +1 -1
  37. data/lib/sidekiq/worker.rb +6 -6
  38. data/lib/sidekiq.rb +17 -5
  39. data/sidekiq.gemspec +2 -2
  40. data/web/assets/javascripts/application.js +22 -19
  41. data/web/assets/javascripts/dashboard.js +2 -2
  42. data/web/assets/stylesheets/application-dark.css +122 -0
  43. data/web/assets/stylesheets/application.css +9 -0
  44. data/web/locales/de.yml +14 -2
  45. data/web/locales/en.yml +2 -0
  46. data/web/locales/fr.yml +2 -2
  47. data/web/locales/ja.yml +2 -0
  48. data/web/locales/lt.yml +83 -0
  49. data/web/locales/vi.yml +83 -0
  50. data/web/views/_job_info.erb +2 -1
  51. data/web/views/busy.erb +4 -1
  52. data/web/views/dead.erb +2 -2
  53. data/web/views/layout.erb +1 -0
  54. data/web/views/morgue.erb +4 -1
  55. data/web/views/queue.erb +10 -1
  56. data/web/views/queues.erb +8 -0
  57. data/web/views/retries.erb +4 -1
  58. data/web/views/retry.erb +2 -2
  59. data/web/views/scheduled.erb +4 -1
  60. metadata +13 -8
@@ -14,18 +14,19 @@ module Sidekiq
14
14
  # Just check Redis for the set of jobs with a timestamp before now.
15
15
  Sidekiq.redis do |conn|
16
16
  sorted_sets.each do |sorted_set|
17
- # Get the next item in the queue if it's score (time to execute) is <= now.
18
- # We need to go through the list one at a time to reduce the risk of something
19
- # going wrong between the time jobs are popped from the scheduled queue and when
20
- # they are pushed onto a work queue and losing the jobs.
21
- while (job = conn.zrangebyscore(sorted_set, "-inf", now, limit: [0, 1]).first)
22
-
23
- # Pop item off the queue and add it to the work queue. If the job can't be popped from
24
- # the queue, it's because another process already popped it so we can move on to the
25
- # next one.
26
- if conn.zrem(sorted_set, job)
27
- Sidekiq::Client.push(Sidekiq.load_json(job))
28
- Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
17
+ # Get next items in the queue with scores (time to execute) <= now.
18
+ until (jobs = conn.zrangebyscore(sorted_set, "-inf", now, limit: [0, 100])).empty?
19
+ # We need to go through the list one at a time to reduce the risk of something
20
+ # going wrong between the time jobs are popped from the scheduled queue and when
21
+ # they are pushed onto a work queue and losing the jobs.
22
+ jobs.each do |job|
23
+ # Pop item off the queue and add it to the work queue. If the job can't be popped from
24
+ # the queue, it's because another process already popped it so we can move on to the
25
+ # next one.
26
+ if conn.zrem(sorted_set, job)
27
+ Sidekiq::Client.push(Sidekiq.load_json(job))
28
+ Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
29
+ end
29
30
  end
30
31
  end
31
32
  end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2017, 2018, 2019, 2020 Agis Anastasopoulos
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
8
+ # this software and associated documentation files (the "Software"), to deal in
9
+ # the Software without restriction, including without limitation the rights to
10
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
+ # the Software, and to permit persons to whom the Software is furnished to do so,
12
+ # subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ # This is a copy of https://github.com/agis/ruby-sdnotify as of commit a7d52ee
25
+ # The only changes made was "rehoming" it within the Sidekiq module to avoid
26
+ # namespace collisions and applying standard's code formatting style.
27
+
28
+ require "socket"
29
+
30
+ # SdNotify is a pure-Ruby implementation of sd_notify(3). It can be used to
31
+ # notify systemd about state changes. Methods of this package are no-op on
32
+ # non-systemd systems (eg. Darwin).
33
+ #
34
+ # The API maps closely to the original implementation of sd_notify(3),
35
+ # therefore be sure to check the official man pages prior to using SdNotify.
36
+ #
37
+ # @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
38
+ module Sidekiq
39
+ module SdNotify
40
+ # Exception raised when there's an error writing to the notification socket
41
+ class NotifyError < RuntimeError; end
42
+
43
+ READY = "READY=1"
44
+ RELOADING = "RELOADING=1"
45
+ STOPPING = "STOPPING=1"
46
+ STATUS = "STATUS="
47
+ ERRNO = "ERRNO="
48
+ MAINPID = "MAINPID="
49
+ WATCHDOG = "WATCHDOG=1"
50
+ FDSTORE = "FDSTORE=1"
51
+
52
+ def self.ready(unset_env = false)
53
+ notify(READY, unset_env)
54
+ end
55
+
56
+ def self.reloading(unset_env = false)
57
+ notify(RELOADING, unset_env)
58
+ end
59
+
60
+ def self.stopping(unset_env = false)
61
+ notify(STOPPING, unset_env)
62
+ end
63
+
64
+ # @param status [String] a custom status string that describes the current
65
+ # state of the service
66
+ def self.status(status, unset_env = false)
67
+ notify("#{STATUS}#{status}", unset_env)
68
+ end
69
+
70
+ # @param errno [Integer]
71
+ def self.errno(errno, unset_env = false)
72
+ notify("#{ERRNO}#{errno}", unset_env)
73
+ end
74
+
75
+ # @param pid [Integer]
76
+ def self.mainpid(pid, unset_env = false)
77
+ notify("#{MAINPID}#{pid}", unset_env)
78
+ end
79
+
80
+ def self.watchdog(unset_env = false)
81
+ notify(WATCHDOG, unset_env)
82
+ end
83
+
84
+ def self.fdstore(unset_env = false)
85
+ notify(FDSTORE, unset_env)
86
+ end
87
+
88
+ # @param [Boolean] true if the service manager expects watchdog keep-alive
89
+ # notification messages to be sent from this process.
90
+ #
91
+ # If the $WATCHDOG_USEC environment variable is set,
92
+ # and the $WATCHDOG_PID variable is unset or set to the PID of the current
93
+ # process
94
+ #
95
+ # @note Unlike sd_watchdog_enabled(3), this method does not mutate the
96
+ # environment.
97
+ def self.watchdog?
98
+ wd_usec = ENV["WATCHDOG_USEC"]
99
+ wd_pid = ENV["WATCHDOG_PID"]
100
+
101
+ return false unless wd_usec
102
+
103
+ begin
104
+ wd_usec = Integer(wd_usec)
105
+ rescue
106
+ return false
107
+ end
108
+
109
+ return false if wd_usec <= 0
110
+ return true if !wd_pid || wd_pid == $$.to_s
111
+
112
+ false
113
+ end
114
+
115
+ # Notify systemd with the provided state, via the notification socket, if
116
+ # any.
117
+ #
118
+ # Generally this method will be used indirectly through the other methods
119
+ # of the library.
120
+ #
121
+ # @param state [String]
122
+ # @param unset_env [Boolean]
123
+ #
124
+ # @return [Fixnum, nil] the number of bytes written to the notification
125
+ # socket or nil if there was no socket to report to (eg. the program wasn't
126
+ # started by systemd)
127
+ #
128
+ # @raise [NotifyError] if there was an error communicating with the systemd
129
+ # socket
130
+ #
131
+ # @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
132
+ def self.notify(state, unset_env = false)
133
+ sock = ENV["NOTIFY_SOCKET"]
134
+
135
+ return nil unless sock
136
+
137
+ ENV.delete("NOTIFY_SOCKET") if unset_env
138
+
139
+ begin
140
+ Addrinfo.unix(sock, :DGRAM).connect do |s|
141
+ s.close_on_exec = true
142
+ s.write(state)
143
+ end
144
+ rescue => e
145
+ raise NotifyError, "#{e.class}: #{e.message}", e.backtrace
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,24 @@
1
+ #
2
+ # Sidekiq's systemd integration allows Sidekiq to inform systemd:
3
+ # 1. when it has successfully started
4
+ # 2. when it is starting shutdown
5
+ # 3. periodically for a liveness check with a watchdog thread
6
+ #
7
+ module Sidekiq
8
+ def self.start_watchdog
9
+ usec = Integer(ENV["WATCHDOG_USEC"])
10
+ return Sidekiq.logger.error("systemd Watchdog too fast: " + usec) if usec < 1_000_000
11
+
12
+ sec_f = usec / 1_000_000.0
13
+ # "It is recommended that a daemon sends a keep-alive notification message
14
+ # to the service manager every half of the time returned here."
15
+ ping_f = sec_f / 2
16
+ Sidekiq.logger.info "Pinging systemd watchdog every #{ping_f.round(1)} sec"
17
+ Thread.new do
18
+ loop do
19
+ sleep ping_f
20
+ Sidekiq::SdNotify.watchdog
21
+ end
22
+ end
23
+ end
24
+ end
@@ -323,6 +323,18 @@ module Sidekiq
323
323
  end
324
324
  end
325
325
  end
326
+
327
+ module TestingExtensions
328
+ def jobs_for(klass)
329
+ jobs.select do |job|
330
+ marshalled = job["args"][0]
331
+ marshalled.index(klass.to_s) && YAML.load(marshalled)[0] == klass
332
+ end
333
+ end
334
+ end
335
+
336
+ Sidekiq::Extensions::DelayedMailer.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedMailer)
337
+ Sidekiq::Extensions::DelayedModel.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedModel)
326
338
  end
327
339
 
328
340
  if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test?
data/lib/sidekiq/util.rb CHANGED
@@ -11,8 +11,6 @@ module Sidekiq
11
11
  module Util
12
12
  include ExceptionHandler
13
13
 
14
- EXPIRY = 60 * 60 * 24
15
-
16
14
  def watchdog(last_words)
17
15
  yield
18
16
  rescue Exception => ex
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "6.0.0"
4
+ VERSION = "6.0.7"
5
5
  end
@@ -5,7 +5,6 @@ module Sidekiq
5
5
  extend WebRouter
6
6
 
7
7
  CONTENT_LENGTH = "Content-Length"
8
- CONTENT_TYPE = "Content-Type"
9
8
  REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human]
10
9
  CSP_HEADER = [
11
10
  "default-src 'self' https: http:",
@@ -20,7 +19,7 @@ module Sidekiq
20
19
  "script-src 'self' https: http: 'unsafe-inline'",
21
20
  "style-src 'self' https: http: 'unsafe-inline'",
22
21
  "worker-src 'self'",
23
- "base-uri 'self'",
22
+ "base-uri 'self'"
24
23
  ].join("; ").freeze
25
24
 
26
25
  def initialize(klass)
@@ -84,14 +83,22 @@ module Sidekiq
84
83
 
85
84
  @count = (params["count"] || 25).to_i
86
85
  @queue = Sidekiq::Queue.new(@name)
87
- (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count)
86
+ (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc")
88
87
  @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
89
88
 
90
89
  erb(:queue)
91
90
  end
92
91
 
93
92
  post "/queues/:name" do
94
- Sidekiq::Queue.new(route_params[:name]).clear
93
+ queue = Sidekiq::Queue.new(route_params[:name])
94
+
95
+ if Sidekiq.pro? && params["pause"]
96
+ queue.pause!
97
+ elsif Sidekiq.pro? && params["unpause"]
98
+ queue.unpause!
99
+ else
100
+ queue.clear
101
+ end
95
102
 
96
103
  redirect "#{root_path}queues"
97
104
  end
@@ -268,7 +275,7 @@ module Sidekiq
268
275
  scheduled: sidekiq_stats.scheduled_size,
269
276
  retries: sidekiq_stats.retry_size,
270
277
  dead: sidekiq_stats.dead_size,
271
- default_latency: sidekiq_stats.default_queue_latency,
278
+ default_latency: sidekiq_stats.default_queue_latency
272
279
  },
273
280
  redis: redis_stats,
274
281
  server_utc_time: server_utc_time
@@ -283,36 +290,30 @@ module Sidekiq
283
290
  action = self.class.match(env)
284
291
  return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found"]] unless action
285
292
 
286
- resp = catch(:halt) {
287
- app = @klass
293
+ app = @klass
294
+ resp = catch(:halt) do # rubocop:disable Standard/SemanticBlocks
288
295
  self.class.run_befores(app, action)
289
- begin
290
- resp = action.instance_exec env, &action.block
291
- ensure
292
- self.class.run_afters(app, action)
293
- end
294
-
295
- resp
296
- }
296
+ action.instance_exec env, &action.block
297
+ ensure
298
+ self.class.run_afters(app, action)
299
+ end
297
300
 
298
301
  resp = case resp
299
302
  when Array
303
+ # redirects go here
300
304
  resp
301
305
  else
306
+ # rendered content goes here
302
307
  headers = {
303
308
  "Content-Type" => "text/html",
304
309
  "Cache-Control" => "no-cache",
305
310
  "Content-Language" => action.locale,
306
- "Content-Security-Policy" => CSP_HEADER,
311
+ "Content-Security-Policy" => CSP_HEADER
307
312
  }
308
-
313
+ # we'll let Rack calculate Content-Length for us.
309
314
  [200, headers, [resp]]
310
315
  end
311
316
 
312
- resp[1] = resp[1].dup
313
-
314
- resp[1][CONTENT_LENGTH] = resp[2].inject(0) { |l, p| l + p.bytesize }.to_s
315
-
316
317
  resp
317
318
  end
318
319
 
@@ -65,7 +65,10 @@ module Sidekiq
65
65
 
66
66
  def poll_path
67
67
  if current_path != "" && params["poll"]
68
- root_path + current_path
68
+ path = root_path + current_path
69
+ query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
70
+ path += "?#{query_string}" unless query_string.empty?
71
+ path
69
72
  else
70
73
  ""
71
74
  end
@@ -112,6 +115,13 @@ module Sidekiq
112
115
  end
113
116
  end
114
117
 
118
+ # within is used by Sidekiq Pro
119
+ def display_tags(job, within = nil)
120
+ job.tags.map { |tag|
121
+ "<span class='jobtag label label-info'>#{::Rack::Utils.escape_html(tag)}</span>"
122
+ }.join(" ")
123
+ end
124
+
115
125
  # mperham/sidekiq#3243
116
126
  def unfiltered?
117
127
  yield unless env["PATH_INFO"].start_with?("/filter/")
@@ -130,6 +140,10 @@ module Sidekiq
130
140
  end
131
141
  end
132
142
 
143
+ def sort_direction_label
144
+ params[:direction] == "asc" ? "&uarr;" : "&darr;"
145
+ end
146
+
133
147
  def workers
134
148
  @workers ||= Sidekiq::Workers.new
135
149
  end
@@ -142,12 +156,6 @@ module Sidekiq
142
156
  @stats ||= Sidekiq::Stats.new
143
157
  end
144
158
 
145
- def retries_with_score(score)
146
- Sidekiq.redis { |conn|
147
- conn.zrangebyscore("retry", score, score)
148
- }.map { |msg| Sidekiq.load_json(msg) }
149
- end
150
-
151
159
  def redis_connection
152
160
  Sidekiq.redis do |conn|
153
161
  c = conn.connection
@@ -189,7 +197,7 @@ module Sidekiq
189
197
  [score.to_f, jid]
190
198
  end
191
199
 
192
- SAFE_QPARAMS = %w[page poll]
200
+ SAFE_QPARAMS = %w[page poll direction]
193
201
 
194
202
  # Merge options with current params, filter safe params, and stringify to query string
195
203
  def qparams(options)
@@ -198,7 +206,11 @@ module Sidekiq
198
206
  options[key.to_s] = options.delete(key)
199
207
  end
200
208
 
201
- params.merge(options).map { |key, value|
209
+ to_query_string(params.merge(options))
210
+ end
211
+
212
+ def to_query_string(params)
213
+ params.map { |key, value|
202
214
  SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
203
215
  }.compact.join("&")
204
216
  end
@@ -238,7 +250,7 @@ module Sidekiq
238
250
  queue class args retry_count retried_at failed_at
239
251
  jid error_message error_class backtrace
240
252
  error_backtrace enqueued_at retry wrapped
241
- created_at
253
+ created_at tags
242
254
  ])
243
255
 
244
256
  def retry_extra_items(retry_job)
@@ -283,7 +295,7 @@ module Sidekiq
283
295
  end
284
296
 
285
297
  def environment_title_prefix
286
- environment = Sidekiq.options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
298
+ environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
287
299
 
288
300
  "[#{environment.upcase}] " unless environment == "production"
289
301
  end
@@ -94,9 +94,7 @@ module Sidekiq
94
94
  {} if path == matcher
95
95
  else
96
96
  path_match = path.match(matcher)
97
- if path_match
98
- Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
99
- end
97
+ path_match&.named_captures&.transform_keys(&:to_sym)
100
98
  end
101
99
  end
102
100
  end
data/lib/sidekiq/web.rb CHANGED
@@ -31,7 +31,7 @@ module Sidekiq
31
31
  "Queues" => "queues",
32
32
  "Retries" => "retries",
33
33
  "Scheduled" => "scheduled",
34
- "Dead" => "morgue",
34
+ "Dead" => "morgue"
35
35
  }
36
36
 
37
37
  class << self
@@ -48,8 +48,8 @@ module Sidekiq
48
48
  # In practice, any option is allowed. This is the main mechanism to configure the
49
49
  # options for a specific job.
50
50
  def sidekiq_options(opts = {})
51
- opts = Hash[opts.map { |k, v| [k.to_s, v] }] # stringify
52
- self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map { |k, v| [k.to_s, v] }])
51
+ opts = opts.transform_keys(&:to_s) # stringify
52
+ self.sidekiq_options_hash = get_sidekiq_options.merge(opts)
53
53
  end
54
54
 
55
55
  def sidekiq_retry_in(&block)
@@ -171,9 +171,9 @@ module Sidekiq
171
171
  now = Time.now.to_f
172
172
  ts = (int < 1_000_000_000 ? now + int : int)
173
173
 
174
- payload = @opts.merge("class" => @klass, "args" => args, "at" => ts)
174
+ payload = @opts.merge("class" => @klass, "args" => args)
175
175
  # Optimization to enqueue something now that is scheduled to go out now or in the past
176
- payload.delete("at") if ts <= now
176
+ payload["at"] = ts if ts > now
177
177
  @klass.client_push(payload)
178
178
  end
179
179
  alias_method :perform_at, :perform_in
@@ -207,10 +207,10 @@ module Sidekiq
207
207
  now = Time.now.to_f
208
208
  ts = (int < 1_000_000_000 ? now + int : int)
209
209
 
210
- item = {"class" => self, "args" => args, "at" => ts}
210
+ item = {"class" => self, "args" => args}
211
211
 
212
212
  # Optimization to enqueue something now that is scheduled to go out now or in the past
213
- item.delete("at") if ts <= now
213
+ item["at"] = ts if ts > now
214
214
 
215
215
  client_push(item)
216
216
  end
data/lib/sidekiq.rb CHANGED
@@ -30,16 +30,16 @@ module Sidekiq
30
30
  startup: [],
31
31
  quiet: [],
32
32
  shutdown: [],
33
- heartbeat: [],
33
+ heartbeat: []
34
34
  },
35
35
  dead_max_jobs: 10_000,
36
36
  dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
37
- reloader: proc { |&block| block.call },
37
+ reloader: proc { |&block| block.call }
38
38
  }
39
39
 
40
40
  DEFAULT_WORKER_OPTIONS = {
41
41
  "retry" => true,
42
- "queue" => "default",
42
+ "queue" => "default"
43
43
  }
44
44
 
45
45
  FAKE_INFO = {
@@ -47,7 +47,7 @@ module Sidekiq
47
47
  "uptime_in_days" => "9999",
48
48
  "connected_clients" => "9999",
49
49
  "used_memory_human" => "9P",
50
- "used_memory_peak_human" => "9P",
50
+ "used_memory_peak_human" => "9P"
51
51
  }
52
52
 
53
53
  def self.❨╯°□°❩╯︵┻━┻
@@ -154,7 +154,7 @@ module Sidekiq
154
154
 
155
155
  def self.default_worker_options=(hash)
156
156
  # stringify
157
- @default_worker_options = default_worker_options.merge(Hash[hash.map { |k, v| [k.to_s, v] }])
157
+ @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
158
158
  end
159
159
 
160
160
  def self.default_worker_options
@@ -192,6 +192,7 @@ module Sidekiq
192
192
 
193
193
  def self.log_formatter=(log_formatter)
194
194
  @log_formatter = log_formatter
195
+ logger.formatter = log_formatter
195
196
  end
196
197
 
197
198
  def self.logger
@@ -199,9 +200,20 @@ module Sidekiq
199
200
  end
200
201
 
201
202
  def self.logger=(logger)
203
+ if logger.nil?
204
+ self.logger.level = Logger::FATAL
205
+ return self.logger
206
+ end
207
+
208
+ logger.extend(Sidekiq::LoggingUtils)
209
+
202
210
  @logger = logger
203
211
  end
204
212
 
213
+ def self.pro?
214
+ defined?(Sidekiq::Pro)
215
+ end
216
+
205
217
  # How frequently Redis should be checked by a random Sidekiq process for
206
218
  # scheduled and retriable jobs. Each individual process will take turns by
207
219
  # waiting some multiple of this value.
data/sidekiq.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.homepage = "http://sidekiq.org"
9
9
  gem.license = "LGPL-3.0"
10
10
 
11
- gem.executables = ["sidekiq"]
11
+ gem.executables = ["sidekiq", "sidekiqmon"]
12
12
  gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
13
13
  gem.name = "sidekiq"
14
14
  gem.version = Sidekiq::VERSION
@@ -16,6 +16,6 @@ Gem::Specification.new do |gem|
16
16
 
17
17
  gem.add_dependency "redis", ">= 4.1.0"
18
18
  gem.add_dependency "connection_pool", ">= 2.2.2"
19
- gem.add_dependency "rack", ">= 2.0.0"
19
+ gem.add_dependency "rack", "~> 2.0"
20
20
  gem.add_dependency "rack-protection", ">= 2.0.0"
21
21
  end
@@ -19,7 +19,8 @@ Sidekiq = {};
19
19
  $(function() {
20
20
  var pollpath = $('body').data('poll-path');
21
21
  if (pollpath != "") {
22
- updatePage(pollpath);
22
+ var ti = parseInt(localStorage.timeInterval) || 2000;
23
+ setTimeout(function(){updatePage(pollpath)}, ti);
23
24
  }
24
25
 
25
26
  $(document).on('click', '.check_all', function() {
@@ -55,26 +56,28 @@ function updateFuzzyTimes(locale) {
55
56
  }
56
57
 
57
58
  function updatePage(url) {
58
- setInterval(function () {
59
- $.ajax({
60
- url: url,
61
- dataType: 'html'
62
- }).done(function (data) {
63
- $data = $(data)
64
-
65
- var $page = $data.filter('#page')
66
- $('#page').replaceWith($page)
67
-
68
- var $header_status = $data.find('.status')
69
- $('.status').replaceWith($header_status)
70
-
71
- updateFuzzyTimes($('body').data('locale'));
72
- })
73
- }, parseInt(localStorage.timeInterval) || 2000);
59
+ $.ajax({
60
+ url: url,
61
+ dataType: 'html'
62
+ }).done(function(data) {
63
+ $data = $(data)
64
+
65
+ var $page = $data.filter('#page')
66
+ $('#page').replaceWith($page)
67
+
68
+ var $header_status = $data.find('.status')
69
+ $('.status').replaceWith($header_status)
70
+
71
+ updateFuzzyTimes($('body').data('locale'));
72
+
73
+ var ti = parseInt(localStorage.timeInterval) || 2000;
74
+ setTimeout(function(){updatePage(url)}, ti)
75
+ }).fail(function() {
76
+ var ti = parseInt(localStorage.timeInterval) || 2000;
77
+ setTimeout(function(){updatePage(url)}, ti)
78
+ })
74
79
  }
75
80
 
76
-
77
-
78
81
  $(function() {
79
82
  'use strict';
80
83
 
@@ -27,7 +27,7 @@ var realtimeGraph = function(updatePath) {
27
27
  renderer: 'line',
28
28
  interpolation: 'linear',
29
29
 
30
- series: new Rickshaw.Series.FixedDuration([{ name: graphElement.dataset.failedLabel, color: '#B1003E' }, { name: graphElement.dataset.processedLabel, color: '#006f68' }], undefined, {
30
+ series: new Rickshaw.Series.FixedDuration([{ name: graphElement.dataset.failedLabel, color: '#af0014' }, { name: graphElement.dataset.processedLabel, color: '#006f68' }], undefined, {
31
31
  timeInterval: timeInterval,
32
32
  maxDataPoints: 100,
33
33
  })
@@ -125,7 +125,7 @@ var historyGraph = function() {
125
125
  interpolation: 'linear',
126
126
  series: [
127
127
  {
128
- color: "#B1003E",
128
+ color: "#af0014",
129
129
  data: failed,
130
130
  name: graphElement.dataset.failedLabel
131
131
  }, {