sidekiq 5.2.8 → 6.2.2

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +248 -0
  3. data/LICENSE +1 -1
  4. data/README.md +18 -34
  5. data/bin/sidekiq +26 -2
  6. data/bin/sidekiqload +32 -24
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  9. data/lib/generators/sidekiq/worker_generator.rb +21 -13
  10. data/lib/sidekiq/api.rb +310 -249
  11. data/lib/sidekiq/cli.rb +144 -180
  12. data/lib/sidekiq/client.rb +64 -48
  13. data/lib/sidekiq/delay.rb +5 -6
  14. data/lib/sidekiq/exception_handler.rb +10 -12
  15. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  16. data/lib/sidekiq/extensions/active_record.rb +13 -10
  17. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  18. data/lib/sidekiq/extensions/generic_proxy.rb +6 -4
  19. data/lib/sidekiq/fetch.rb +38 -31
  20. data/lib/sidekiq/job.rb +8 -0
  21. data/lib/sidekiq/job_logger.rb +45 -7
  22. data/lib/sidekiq/job_retry.rb +64 -67
  23. data/lib/sidekiq/launcher.rb +146 -60
  24. data/lib/sidekiq/logger.rb +166 -0
  25. data/lib/sidekiq/manager.rb +11 -13
  26. data/lib/sidekiq/middleware/chain.rb +20 -8
  27. data/lib/sidekiq/middleware/i18n.rb +5 -7
  28. data/lib/sidekiq/monitor.rb +133 -0
  29. data/lib/sidekiq/paginator.rb +18 -14
  30. data/lib/sidekiq/processor.rb +71 -70
  31. data/lib/sidekiq/rails.rb +29 -37
  32. data/lib/sidekiq/redis_connection.rb +50 -48
  33. data/lib/sidekiq/scheduled.rb +35 -30
  34. data/lib/sidekiq/sd_notify.rb +149 -0
  35. data/lib/sidekiq/systemd.rb +24 -0
  36. data/lib/sidekiq/testing/inline.rb +2 -1
  37. data/lib/sidekiq/testing.rb +36 -27
  38. data/lib/sidekiq/util.rb +45 -16
  39. data/lib/sidekiq/version.rb +2 -1
  40. data/lib/sidekiq/web/action.rb +15 -11
  41. data/lib/sidekiq/web/application.rb +86 -76
  42. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  43. data/lib/sidekiq/web/helpers.rb +114 -86
  44. data/lib/sidekiq/web/router.rb +23 -19
  45. data/lib/sidekiq/web.rb +61 -105
  46. data/lib/sidekiq/worker.rb +126 -102
  47. data/lib/sidekiq.rb +69 -44
  48. data/sidekiq.gemspec +23 -16
  49. data/web/assets/images/apple-touch-icon.png +0 -0
  50. data/web/assets/javascripts/application.js +25 -27
  51. data/web/assets/javascripts/dashboard.js +4 -23
  52. data/web/assets/stylesheets/application-dark.css +147 -0
  53. data/web/assets/stylesheets/application.css +37 -128
  54. data/web/locales/ar.yml +8 -2
  55. data/web/locales/de.yml +14 -2
  56. data/web/locales/en.yml +5 -0
  57. data/web/locales/es.yml +18 -2
  58. data/web/locales/fr.yml +10 -3
  59. data/web/locales/ja.yml +7 -1
  60. data/web/locales/lt.yml +83 -0
  61. data/web/locales/pl.yml +4 -4
  62. data/web/locales/ru.yml +4 -0
  63. data/web/locales/vi.yml +83 -0
  64. data/web/views/_job_info.erb +3 -2
  65. data/web/views/busy.erb +54 -20
  66. data/web/views/dashboard.erb +14 -6
  67. data/web/views/dead.erb +3 -3
  68. data/web/views/layout.erb +2 -0
  69. data/web/views/morgue.erb +9 -6
  70. data/web/views/queue.erb +11 -2
  71. data/web/views/queues.erb +10 -2
  72. data/web/views/retries.erb +11 -8
  73. data/web/views/retry.erb +3 -3
  74. data/web/views/scheduled.erb +5 -2
  75. metadata +32 -64
  76. data/.circleci/config.yml +0 -61
  77. data/.github/contributing.md +0 -32
  78. data/.github/issue_template.md +0 -11
  79. data/.gitignore +0 -15
  80. data/.travis.yml +0 -11
  81. data/3.0-Upgrade.md +0 -70
  82. data/4.0-Upgrade.md +0 -53
  83. data/5.0-Upgrade.md +0 -56
  84. data/COMM-LICENSE +0 -97
  85. data/Ent-Changes.md +0 -238
  86. data/Gemfile +0 -23
  87. data/Pro-2.0-Upgrade.md +0 -138
  88. data/Pro-3.0-Upgrade.md +0 -44
  89. data/Pro-4.0-Upgrade.md +0 -35
  90. data/Pro-Changes.md +0 -759
  91. data/Rakefile +0 -9
  92. data/bin/sidekiqctl +0 -20
  93. data/code_of_conduct.md +0 -50
  94. data/lib/sidekiq/core_ext.rb +0 -1
  95. data/lib/sidekiq/ctl.rb +0 -221
  96. data/lib/sidekiq/logging.rb +0 -122
  97. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ # this file originally based on authenticity_token.rb from the sinatra/rack-protection project
4
+ #
5
+ # The MIT License (MIT)
6
+ #
7
+ # Copyright (c) 2011-2017 Konstantin Haase
8
+ # Copyright (c) 2015-2017 Zachary Scott
9
+ #
10
+ # Permission is hereby granted, free of charge, to any person obtaining
11
+ # a copy of this software and associated documentation files (the
12
+ # 'Software'), to deal in the Software without restriction, including
13
+ # without limitation the rights to use, copy, modify, merge, publish,
14
+ # distribute, sublicense, and/or sell copies of the Software, and to
15
+ # permit persons to whom the Software is furnished to do so, subject to
16
+ # the following conditions:
17
+ #
18
+ # The above copyright notice and this permission notice shall be
19
+ # included in all copies or substantial portions of the Software.
20
+ #
21
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
22
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
+
29
+ require "securerandom"
30
+ require "base64"
31
+ require "rack/request"
32
+
33
+ module Sidekiq
34
+ class Web
35
+ class CsrfProtection
36
+ def initialize(app, options = nil)
37
+ @app = app
38
+ end
39
+
40
+ def call(env)
41
+ accept?(env) ? admit(env) : deny(env)
42
+ end
43
+
44
+ private
45
+
46
+ def admit(env)
47
+ # On each successful request, we create a fresh masked token
48
+ # which will be used in any forms rendered for this request.
49
+ s = session(env)
50
+ s[:csrf] ||= SecureRandom.base64(TOKEN_LENGTH)
51
+ env[:csrf_token] = mask_token(s[:csrf])
52
+ @app.call(env)
53
+ end
54
+
55
+ def safe?(env)
56
+ %w[GET HEAD OPTIONS TRACE].include? env["REQUEST_METHOD"]
57
+ end
58
+
59
+ def logger(env)
60
+ @logger ||= (env["rack.logger"] || ::Logger.new(env["rack.errors"]))
61
+ end
62
+
63
+ def deny(env)
64
+ logger(env).warn "attack prevented by #{self.class}"
65
+ [403, {"Content-Type" => "text/plain"}, ["Forbidden"]]
66
+ end
67
+
68
+ def session(env)
69
+ env["rack.session"] || fail(<<~EOM)
70
+ Sidekiq::Web needs a valid Rack session for CSRF protection. If this is a Rails app,
71
+ make sure you mount Sidekiq::Web *inside* your application routes:
72
+
73
+
74
+ Rails.application.routes.draw do
75
+ mount Sidekiq::Web => "/sidekiq"
76
+ ....
77
+ end
78
+
79
+
80
+ If this is a Rails app in API mode, you need to enable sessions.
81
+
82
+ https://guides.rubyonrails.org/api_app.html#using-session-middlewares
83
+
84
+ If this is a bare Rack app, use a session middleware before Sidekiq::Web:
85
+
86
+ # first, use IRB to create a shared secret key for sessions and commit it
87
+ require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) }
88
+
89
+ # now use the secret with a session cookie middleware
90
+ use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400
91
+ run Sidekiq::Web
92
+
93
+ EOM
94
+ end
95
+
96
+ def accept?(env)
97
+ return true if safe?(env)
98
+
99
+ giventoken = ::Rack::Request.new(env).params["authenticity_token"]
100
+ valid_token?(env, giventoken)
101
+ end
102
+
103
+ TOKEN_LENGTH = 32
104
+
105
+ # Checks that the token given to us as a parameter matches
106
+ # the token stored in the session.
107
+ def valid_token?(env, giventoken)
108
+ return false if giventoken.nil? || giventoken.empty?
109
+
110
+ begin
111
+ token = decode_token(giventoken)
112
+ rescue ArgumentError # client input is invalid
113
+ return false
114
+ end
115
+
116
+ sess = session(env)
117
+ localtoken = sess[:csrf]
118
+
119
+ # Checks that Rack::Session::Cookie actualy contains the csrf toekn
120
+ return false if localtoken.nil?
121
+
122
+ # Rotate the session token after every use
123
+ sess[:csrf] = SecureRandom.base64(TOKEN_LENGTH)
124
+
125
+ # See if it's actually a masked token or not. We should be able
126
+ # to handle any unmasked tokens that we've issued without error.
127
+
128
+ if unmasked_token?(token)
129
+ compare_with_real_token token, localtoken
130
+ elsif masked_token?(token)
131
+ unmasked = unmask_token(token)
132
+ compare_with_real_token unmasked, localtoken
133
+ else
134
+ false # Token is malformed
135
+ end
136
+ end
137
+
138
+ # Creates a masked version of the authenticity token that varies
139
+ # on each request. The masking is used to mitigate SSL attacks
140
+ # like BREACH.
141
+ def mask_token(token)
142
+ token = decode_token(token)
143
+ one_time_pad = SecureRandom.random_bytes(token.length)
144
+ encrypted_token = xor_byte_strings(one_time_pad, token)
145
+ masked_token = one_time_pad + encrypted_token
146
+ Base64.strict_encode64(masked_token)
147
+ end
148
+
149
+ # Essentially the inverse of +mask_token+.
150
+ def unmask_token(masked_token)
151
+ # Split the token into the one-time pad and the encrypted
152
+ # value and decrypt it
153
+ token_length = masked_token.length / 2
154
+ one_time_pad = masked_token[0...token_length]
155
+ encrypted_token = masked_token[token_length..-1]
156
+ xor_byte_strings(one_time_pad, encrypted_token)
157
+ end
158
+
159
+ def unmasked_token?(token)
160
+ token.length == TOKEN_LENGTH
161
+ end
162
+
163
+ def masked_token?(token)
164
+ token.length == TOKEN_LENGTH * 2
165
+ end
166
+
167
+ def compare_with_real_token(token, local)
168
+ ::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
169
+ end
170
+
171
+ def decode_token(token)
172
+ Base64.strict_decode64(token)
173
+ end
174
+
175
+ def xor_byte_strings(s1, s2)
176
+ s1.bytes.zip(s2.bytes).map { |(c1, c2)| c1 ^ c2 }.pack("c*")
177
+ end
178
+ end
179
+ end
180
+ end
@@ -1,40 +1,48 @@
1
1
  # frozen_string_literal: true
2
- require 'uri'
3
- require 'set'
4
- require 'yaml'
5
- require 'cgi'
2
+
3
+ require "uri"
4
+ require "set"
5
+ require "yaml"
6
+ require "cgi"
6
7
 
7
8
  module Sidekiq
8
9
  # This is not a public API
9
10
  module WebHelpers
10
11
  def strings(lang)
11
- @@strings ||= {}
12
- @@strings[lang] ||= begin
13
- # Allow sidekiq-web extensions to add locale paths
14
- # so extensions can be localized
15
- settings.locales.each_with_object({}) do |path, global|
16
- find_locale_files(lang).each do |file|
17
- strs = YAML.load(File.open(file))
18
- global.merge!(strs[lang])
19
- end
12
+ @strings ||= {}
13
+
14
+ # Allow sidekiq-web extensions to add locale paths
15
+ # so extensions can be localized
16
+ @strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
17
+ find_locale_files(lang).each do |file|
18
+ strs = YAML.load(File.open(file))
19
+ global.merge!(strs[lang])
20
20
  end
21
21
  end
22
22
  end
23
23
 
24
+ def singularize(str, count)
25
+ if count == 1 && str.respond_to?(:singularize) # rails
26
+ str.singularize
27
+ else
28
+ str
29
+ end
30
+ end
31
+
24
32
  def clear_caches
25
- @@strings = nil
26
- @@locale_files = nil
27
- @@available_locales = nil
33
+ @strings = nil
34
+ @locale_files = nil
35
+ @available_locales = nil
28
36
  end
29
37
 
30
38
  def locale_files
31
- @@locale_files ||= settings.locales.flat_map do |path|
39
+ @locale_files ||= settings.locales.flat_map { |path|
32
40
  Dir["#{path}/*.yml"]
33
- end
41
+ }
34
42
  end
35
43
 
36
44
  def available_locales
37
- @@available_locales ||= locale_files.map { |path| File.basename(path, '.yml') }.uniq
45
+ @available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
38
46
  end
39
47
 
40
48
  def find_locale_files(lang)
@@ -63,32 +71,35 @@ module Sidekiq
63
71
  end
64
72
 
65
73
  def poll_path
66
- if current_path != '' && params['poll']
67
- root_path + current_path
74
+ if current_path != "" && params["poll"]
75
+ path = root_path + current_path
76
+ query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
77
+ path += "?#{query_string}" unless query_string.empty?
78
+ path
68
79
  else
69
80
  ""
70
81
  end
71
82
  end
72
83
 
73
84
  def text_direction
74
- get_locale['TextDirection'] || 'ltr'
85
+ get_locale["TextDirection"] || "ltr"
75
86
  end
76
87
 
77
88
  def rtl?
78
- text_direction == 'rtl'
89
+ text_direction == "rtl"
79
90
  end
80
91
 
81
92
  # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
82
93
  def user_preferred_languages
83
- languages = env['HTTP_ACCEPT_LANGUAGE']
84
- languages.to_s.downcase.gsub(/\s+/, '').split(',').map do |language|
85
- locale, quality = language.split(';q=', 2)
86
- locale = nil if locale == '*' # Ignore wildcards
94
+ languages = env["HTTP_ACCEPT_LANGUAGE"]
95
+ languages.to_s.downcase.gsub(/\s+/, "").split(",").map { |language|
96
+ locale, quality = language.split(";q=", 2)
97
+ locale = nil if locale == "*" # Ignore wildcards
87
98
  quality = quality ? quality.to_f : 1.0
88
99
  [locale, quality]
89
- end.sort do |(_, left), (_, right)|
100
+ }.sort { |(_, left), (_, right)|
90
101
  right <=> left
91
- end.map(&:first).compact
102
+ }.map(&:first).compact
92
103
  end
93
104
 
94
105
  # Given an Accept-Language header like "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2"
@@ -97,31 +108,38 @@ module Sidekiq
97
108
  # Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
98
109
  def locale
99
110
  @locale ||= begin
100
- matched_locale = user_preferred_languages.map do |preferred|
101
- preferred_language = preferred.split('-', 2).first
111
+ matched_locale = user_preferred_languages.map { |preferred|
112
+ preferred_language = preferred.split("-", 2).first
102
113
 
103
- lang_group = available_locales.select do |available|
104
- preferred_language == available.split('-', 2).first
105
- end
114
+ lang_group = available_locales.select { |available|
115
+ preferred_language == available.split("-", 2).first
116
+ }
106
117
 
107
118
  lang_group.find { |lang| lang == preferred } || lang_group.min_by(&:length)
108
- end.compact.first
119
+ }.compact.first
109
120
 
110
- matched_locale || 'en'
121
+ matched_locale || "en"
111
122
  end
112
123
  end
113
124
 
125
+ # within is used by Sidekiq Pro
126
+ def display_tags(job, within = nil)
127
+ job.tags.map { |tag|
128
+ "<span class='label label-info jobtag'>#{::Rack::Utils.escape_html(tag)}</span>"
129
+ }.join(" ")
130
+ end
131
+
114
132
  # mperham/sidekiq#3243
115
133
  def unfiltered?
116
- yield unless env['PATH_INFO'].start_with?("/filter/")
134
+ yield unless env["PATH_INFO"].start_with?("/filter/")
117
135
  end
118
136
 
119
137
  def get_locale
120
138
  strings(locale)
121
139
  end
122
140
 
123
- def t(msg, options={})
124
- string = get_locale[msg] || strings('en')[msg] || msg
141
+ def t(msg, options = {})
142
+ string = get_locale[msg] || strings("en")[msg] || msg
125
143
  if options.empty?
126
144
  string
127
145
  else
@@ -129,6 +147,10 @@ module Sidekiq
129
147
  end
130
148
  end
131
149
 
150
+ def sort_direction_label
151
+ params[:direction] == "asc" ? "&uarr;" : "&darr;"
152
+ end
153
+
132
154
  def workers
133
155
  @workers ||= Sidekiq::Workers.new
134
156
  end
@@ -141,16 +163,9 @@ module Sidekiq
141
163
  @stats ||= Sidekiq::Stats.new
142
164
  end
143
165
 
144
- def retries_with_score(score)
145
- Sidekiq.redis do |conn|
146
- conn.zrangebyscore('retry', score, score)
147
- end.map { |msg| Sidekiq.load_json(msg) }
148
- end
149
-
150
166
  def redis_connection
151
167
  Sidekiq.redis do |conn|
152
- c = conn.connection
153
- "redis://#{c[:location]}/#{c[:db]}"
168
+ conn.connection[:id]
154
169
  end
155
170
  end
156
171
 
@@ -163,24 +178,24 @@ module Sidekiq
163
178
  end
164
179
 
165
180
  def root_path
166
- "#{env['SCRIPT_NAME']}/"
181
+ "#{env["SCRIPT_NAME"]}/"
167
182
  end
168
183
 
169
184
  def current_path
170
- @current_path ||= request.path_info.gsub(/^\//,'')
185
+ @current_path ||= request.path_info.gsub(/^\//, "")
171
186
  end
172
187
 
173
188
  def current_status
174
- workers.size == 0 ? 'idle' : 'active'
189
+ workers.size == 0 ? "idle" : "active"
175
190
  end
176
191
 
177
192
  def relative_time(time)
178
193
  stamp = time.getutc.iso8601
179
- %{<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>}
194
+ %(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
180
195
  end
181
196
 
182
197
  def job_params(job, score)
183
- "#{score}-#{job['jid']}"
198
+ "#{score}-#{job["jid"]}"
184
199
  end
185
200
 
186
201
  def parse_params(params)
@@ -188,18 +203,19 @@ module Sidekiq
188
203
  [score.to_f, jid]
189
204
  end
190
205
 
191
- SAFE_QPARAMS = %w(page poll)
206
+ SAFE_QPARAMS = %w[page poll direction]
192
207
 
193
208
  # Merge options with current params, filter safe params, and stringify to query string
194
209
  def qparams(options)
195
- # stringify
196
- options.keys.each do |key|
197
- options[key.to_s] = options.delete(key)
198
- end
210
+ stringified_options = options.transform_keys(&:to_s)
211
+
212
+ to_query_string(params.merge(stringified_options))
213
+ end
199
214
 
200
- params.merge(options).map do |key, value|
215
+ def to_query_string(params)
216
+ params.map { |key, value|
201
217
  SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
202
- end.compact.join("&")
218
+ }.compact.join("&")
203
219
  end
204
220
 
205
221
  def truncate(text, truncate_after_chars = 2000)
@@ -207,40 +223,38 @@ module Sidekiq
207
223
  end
208
224
 
209
225
  def display_args(args, truncate_after_chars = 2000)
210
- return "Invalid job payload, args is nil" if args == nil
211
- return "Invalid job payload, args must be an Array, not #{args.class.name}" if !args.is_a?(Array)
226
+ return "Invalid job payload, args is nil" if args.nil?
227
+ return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
212
228
 
213
229
  begin
214
- args.map do |arg|
230
+ args.map { |arg|
215
231
  h(truncate(to_display(arg), truncate_after_chars))
216
- end.join(", ")
232
+ }.join(", ")
217
233
  rescue
218
234
  "Illegal job arguments: #{h args.inspect}"
219
235
  end
220
236
  end
221
237
 
222
238
  def csrf_tag
223
- "<input type='hidden' name='authenticity_token' value='#{session[:csrf]}'/>"
239
+ "<input type='hidden' name='authenticity_token' value='#{env[:csrf_token]}'/>"
224
240
  end
225
241
 
226
242
  def to_display(arg)
243
+ arg.inspect
244
+ rescue
227
245
  begin
228
- arg.inspect
229
- rescue
230
- begin
231
- arg.to_s
232
- rescue => ex
233
- "Cannot display argument: [#{ex.class.name}] #{ex.message}"
234
- end
246
+ arg.to_s
247
+ rescue => ex
248
+ "Cannot display argument: [#{ex.class.name}] #{ex.message}"
235
249
  end
236
250
  end
237
251
 
238
- RETRY_JOB_KEYS = Set.new(%w(
252
+ RETRY_JOB_KEYS = Set.new(%w[
239
253
  queue class args retry_count retried_at failed_at
240
254
  jid error_message error_class backtrace
241
255
  error_backtrace enqueued_at retry wrapped
242
- created_at
243
- ))
256
+ created_at tags
257
+ ])
244
258
 
245
259
  def retry_extra_items(retry_job)
246
260
  @retry_extra_items ||= {}.tap do |extra|
@@ -250,15 +264,29 @@ module Sidekiq
250
264
  end
251
265
  end
252
266
 
267
+ def format_memory(rss_kb)
268
+ return "0" if rss_kb.nil? || rss_kb == 0
269
+
270
+ if rss_kb < 100_000
271
+ "#{number_with_delimiter(rss_kb)} KB"
272
+ elsif rss_kb < 10_000_000
273
+ "#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
274
+ else
275
+ "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)).round(1))} GB"
276
+ end
277
+ end
278
+
253
279
  def number_with_delimiter(number)
280
+ return "" if number.nil?
281
+
254
282
  begin
255
283
  Float(number)
256
284
  rescue ArgumentError, TypeError
257
285
  return number
258
286
  end
259
287
 
260
- options = {delimiter: ',', separator: '.'}
261
- parts = number.to_s.to_str.split('.')
288
+ options = {delimiter: ",", separator: "."}
289
+ parts = number.to_s.to_str.split(".")
262
290
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
263
291
  parts.join(options[:separator])
264
292
  end
@@ -266,8 +294,8 @@ module Sidekiq
266
294
  def h(text)
267
295
  ::Rack::Utils.escape_html(text)
268
296
  rescue ArgumentError => e
269
- raise unless e.message.eql?('invalid byte sequence in UTF-8')
270
- text.encode!('UTF-16', 'UTF-8', invalid: :replace, replace: '').encode!('UTF-8', 'UTF-16')
297
+ raise unless e.message.eql?("invalid byte sequence in UTF-8")
298
+ text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
271
299
  retry
272
300
  end
273
301
 
@@ -284,7 +312,7 @@ module Sidekiq
284
312
  end
285
313
 
286
314
  def environment_title_prefix
287
- environment = Sidekiq.options[:environment] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
315
+ environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
288
316
 
289
317
  "[#{environment.upcase}] " unless environment == "production"
290
318
  end
@@ -294,30 +322,30 @@ module Sidekiq
294
322
  end
295
323
 
296
324
  def server_utc_time
297
- Time.now.utc.strftime('%H:%M:%S UTC')
325
+ Time.now.utc.strftime("%H:%M:%S UTC")
298
326
  end
299
327
 
300
328
  def redis_connection_and_namespace
301
329
  @redis_connection_and_namespace ||= begin
302
- namespace_suffix = namespace == nil ? '' : "##{namespace}"
330
+ namespace_suffix = namespace.nil? ? "" : "##{namespace}"
303
331
  "#{redis_connection}#{namespace_suffix}"
304
332
  end
305
333
  end
306
334
 
307
335
  def retry_or_delete_or_kill(job, params)
308
- if params['retry']
336
+ if params["retry"]
309
337
  job.retry
310
- elsif params['delete']
338
+ elsif params["delete"]
311
339
  job.delete
312
- elsif params['kill']
340
+ elsif params["kill"]
313
341
  job.kill
314
342
  end
315
343
  end
316
344
 
317
345
  def delete_or_add_queue(job, params)
318
- if params['delete']
346
+ if params["delete"]
319
347
  job.delete
320
- elsif params['add_to_queue']
348
+ elsif params["add_to_queue"]
321
349
  job.add_to_queue
322
350
  end
323
351
  end