sidekiq 6.4.2 → 6.5.12
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.
- checksums.yaml +4 -4
- data/Changes.md +89 -0
- data/bin/sidekiqload +17 -5
- data/lib/sidekiq/api.rb +196 -45
- data/lib/sidekiq/cli.rb +46 -32
- data/lib/sidekiq/client.rb +6 -6
- data/lib/sidekiq/component.rb +65 -0
- data/lib/sidekiq/delay.rb +1 -1
- data/lib/sidekiq/fetch.rb +18 -16
- data/lib/sidekiq/job_retry.rb +60 -39
- data/lib/sidekiq/job_util.rb +7 -3
- data/lib/sidekiq/launcher.rb +24 -21
- data/lib/sidekiq/logger.rb +1 -1
- data/lib/sidekiq/manager.rb +23 -20
- data/lib/sidekiq/metrics/deploy.rb +47 -0
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +94 -0
- data/lib/sidekiq/metrics/tracking.rb +134 -0
- data/lib/sidekiq/middleware/chain.rb +82 -38
- data/lib/sidekiq/middleware/current_attributes.rb +18 -12
- data/lib/sidekiq/middleware/i18n.rb +2 -0
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +11 -3
- data/lib/sidekiq/processor.rb +21 -15
- data/lib/sidekiq/rails.rb +12 -13
- data/lib/sidekiq/redis_client_adapter.rb +154 -0
- data/lib/sidekiq/redis_connection.rb +78 -47
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +53 -24
- data/lib/sidekiq/testing.rb +1 -1
- data/lib/sidekiq/transaction_aware_client.rb +45 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +21 -5
- data/lib/sidekiq/web/helpers.rb +18 -5
- data/lib/sidekiq/web.rb +5 -1
- data/lib/sidekiq/worker.rb +8 -4
- data/lib/sidekiq.rb +87 -18
- data/sidekiq.gemspec +2 -2
- data/web/assets/javascripts/application.js +2 -1
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard.js +0 -17
- data/web/assets/javascripts/graph.js +16 -0
- data/web/assets/javascripts/metrics.js +262 -0
- data/web/assets/stylesheets/application.css +44 -1
- data/web/locales/el.yml +43 -19
- data/web/locales/en.yml +7 -0
- data/web/locales/ja.yml +7 -0
- data/web/locales/pt-br.yml +27 -9
- data/web/locales/zh-cn.yml +36 -11
- data/web/locales/zh-tw.yml +32 -7
- data/web/views/_nav.erb +1 -1
- data/web/views/busy.erb +7 -2
- data/web/views/dashboard.erb +1 -0
- data/web/views/metrics.erb +69 -0
- data/web/views/metrics_for_job.erb +87 -0
- data/web/views/queue.erb +5 -1
- metadata +34 -9
- data/lib/sidekiq/exception_handler.rb +0 -27
- data/lib/sidekiq/util.rb +0 -108
@@ -5,8 +5,79 @@ require "redis"
|
|
5
5
|
require "uri"
|
6
6
|
|
7
7
|
module Sidekiq
|
8
|
-
|
8
|
+
module RedisConnection
|
9
|
+
class RedisAdapter
|
10
|
+
BaseError = Redis::BaseError
|
11
|
+
CommandError = Redis::CommandError
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
warn("Usage of the 'redis' gem within Sidekiq itself is deprecated, Sidekiq 7.0 will only use the new, simpler 'redis-client' gem", caller) if ENV["SIDEKIQ_REDIS_CLIENT"] == "1"
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_client
|
19
|
+
namespace = @options[:namespace]
|
20
|
+
|
21
|
+
client = Redis.new client_opts(@options)
|
22
|
+
if namespace
|
23
|
+
begin
|
24
|
+
require "redis/namespace"
|
25
|
+
Redis::Namespace.new(namespace, redis: client)
|
26
|
+
rescue LoadError
|
27
|
+
Sidekiq.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \
|
28
|
+
"Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.")
|
29
|
+
exit(-127)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
client
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def client_opts(options)
|
39
|
+
opts = options.dup
|
40
|
+
if opts[:namespace]
|
41
|
+
opts.delete(:namespace)
|
42
|
+
end
|
43
|
+
|
44
|
+
if opts[:network_timeout]
|
45
|
+
opts[:timeout] = opts[:network_timeout]
|
46
|
+
opts.delete(:network_timeout)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Issue #3303, redis-rb will silently retry an operation.
|
50
|
+
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
|
51
|
+
# is performed twice but I believe this is much, much rarer
|
52
|
+
# than the reconnect silently fixing a problem; we keep it
|
53
|
+
# on by default.
|
54
|
+
opts[:reconnect_attempts] ||= 1
|
55
|
+
|
56
|
+
opts
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
@adapter = RedisAdapter
|
61
|
+
|
9
62
|
class << self
|
63
|
+
attr_reader :adapter
|
64
|
+
|
65
|
+
# RedisConnection.adapter = :redis
|
66
|
+
# RedisConnection.adapter = :redis_client
|
67
|
+
def adapter=(adapter)
|
68
|
+
raise "no" if adapter == self
|
69
|
+
result = case adapter
|
70
|
+
when :redis
|
71
|
+
RedisAdapter
|
72
|
+
when Class
|
73
|
+
adapter
|
74
|
+
else
|
75
|
+
require "sidekiq/#{adapter}_adapter"
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
@adapter = result if result
|
79
|
+
end
|
80
|
+
|
10
81
|
def create(options = {})
|
11
82
|
symbolized_options = options.transform_keys(&:to_sym)
|
12
83
|
|
@@ -19,20 +90,21 @@ module Sidekiq
|
|
19
90
|
elsif Sidekiq.server?
|
20
91
|
# Give ourselves plenty of connections. pool is lazy
|
21
92
|
# so we won't create them until we need them.
|
22
|
-
Sidekiq
|
93
|
+
Sidekiq[:concurrency] + 5
|
23
94
|
elsif ENV["RAILS_MAX_THREADS"]
|
24
95
|
Integer(ENV["RAILS_MAX_THREADS"])
|
25
96
|
else
|
26
97
|
5
|
27
98
|
end
|
28
99
|
|
29
|
-
verify_sizing(size, Sidekiq
|
100
|
+
verify_sizing(size, Sidekiq[:concurrency]) if Sidekiq.server?
|
30
101
|
|
31
102
|
pool_timeout = symbolized_options[:pool_timeout] || 1
|
32
103
|
log_info(symbolized_options)
|
33
104
|
|
105
|
+
redis_config = adapter.new(symbolized_options)
|
34
106
|
ConnectionPool.new(timeout: pool_timeout, size: size) do
|
35
|
-
|
107
|
+
redis_config.new_client
|
36
108
|
end
|
37
109
|
end
|
38
110
|
|
@@ -50,47 +122,6 @@ module Sidekiq
|
|
50
122
|
raise ArgumentError, "Your Redis connection pool is too small for Sidekiq. Your pool has #{size} connections but must have at least #{concurrency + 2}" if size < (concurrency + 2)
|
51
123
|
end
|
52
124
|
|
53
|
-
def build_client(options)
|
54
|
-
namespace = options[:namespace]
|
55
|
-
|
56
|
-
client = Redis.new client_opts(options)
|
57
|
-
if namespace
|
58
|
-
begin
|
59
|
-
require "redis/namespace"
|
60
|
-
Redis::Namespace.new(namespace, redis: client)
|
61
|
-
rescue LoadError
|
62
|
-
Sidekiq.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \
|
63
|
-
"Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.")
|
64
|
-
exit(-127)
|
65
|
-
end
|
66
|
-
else
|
67
|
-
client
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def client_opts(options)
|
72
|
-
opts = options.dup
|
73
|
-
if opts[:namespace]
|
74
|
-
opts.delete(:namespace)
|
75
|
-
end
|
76
|
-
|
77
|
-
if opts[:network_timeout]
|
78
|
-
opts[:timeout] = opts[:network_timeout]
|
79
|
-
opts.delete(:network_timeout)
|
80
|
-
end
|
81
|
-
|
82
|
-
opts[:driver] ||= Redis::Connection.drivers.last || "ruby"
|
83
|
-
|
84
|
-
# Issue #3303, redis-rb will silently retry an operation.
|
85
|
-
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
|
86
|
-
# is performed twice but I believe this is much, much rarer
|
87
|
-
# than the reconnect silently fixing a problem; we keep it
|
88
|
-
# on by default.
|
89
|
-
opts[:reconnect_attempts] ||= 1
|
90
|
-
|
91
|
-
opts
|
92
|
-
end
|
93
|
-
|
94
125
|
def log_info(options)
|
95
126
|
redacted = "REDACTED"
|
96
127
|
|
@@ -110,9 +141,9 @@ module Sidekiq
|
|
110
141
|
sentinel[:password] = redacted if sentinel[:password]
|
111
142
|
end
|
112
143
|
if Sidekiq.server?
|
113
|
-
Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with
|
144
|
+
Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with #{adapter.name} options #{scrubbed_options}")
|
114
145
|
else
|
115
|
-
Sidekiq.logger.debug("#{Sidekiq::NAME} client with
|
146
|
+
Sidekiq.logger.debug("#{Sidekiq::NAME} client with #{adapter.name} options #{scrubbed_options}")
|
116
147
|
end
|
117
148
|
end
|
118
149
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
class RingBuffer
|
5
|
+
include Enumerable
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@buf, :[], :each, :size
|
8
|
+
|
9
|
+
def initialize(size, default = 0)
|
10
|
+
@size = size
|
11
|
+
@buf = Array.new(size, default)
|
12
|
+
@index = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(element)
|
16
|
+
@buf[@index % @size] = element
|
17
|
+
@index += 1
|
18
|
+
element
|
19
|
+
end
|
20
|
+
|
21
|
+
def buffer
|
22
|
+
@buf
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset(default = 0)
|
26
|
+
@buf.fill(default)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sidekiq/scheduled.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sidekiq"
|
4
|
-
require "sidekiq/
|
5
|
-
require "sidekiq/api"
|
4
|
+
require "sidekiq/component"
|
6
5
|
|
7
6
|
module Sidekiq
|
8
7
|
module Scheduled
|
@@ -52,8 +51,8 @@ module Sidekiq
|
|
52
51
|
@lua_zpopbyscore_sha = raw_conn.script(:load, LUA_ZPOPBYSCORE)
|
53
52
|
end
|
54
53
|
|
55
|
-
conn.evalsha(@lua_zpopbyscore_sha, keys
|
56
|
-
rescue
|
54
|
+
conn.evalsha(@lua_zpopbyscore_sha, keys, argv)
|
55
|
+
rescue RedisConnection.adapter::CommandError => e
|
57
56
|
raise unless e.message.start_with?("NOSCRIPT")
|
58
57
|
|
59
58
|
@lua_zpopbyscore_sha = nil
|
@@ -67,12 +66,13 @@ module Sidekiq
|
|
67
66
|
# just pops the job back onto its original queue so the
|
68
67
|
# workers can pick it up like any other job.
|
69
68
|
class Poller
|
70
|
-
include
|
69
|
+
include Sidekiq::Component
|
71
70
|
|
72
71
|
INITIAL_WAIT = 10
|
73
72
|
|
74
|
-
def initialize
|
75
|
-
@
|
73
|
+
def initialize(options)
|
74
|
+
@config = options
|
75
|
+
@enq = (options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
|
76
76
|
@sleeper = ConnectionPool::TimedStack.new
|
77
77
|
@done = false
|
78
78
|
@thread = nil
|
@@ -100,7 +100,7 @@ module Sidekiq
|
|
100
100
|
enqueue
|
101
101
|
wait
|
102
102
|
end
|
103
|
-
|
103
|
+
logger.info("Scheduler exiting...")
|
104
104
|
}
|
105
105
|
end
|
106
106
|
|
@@ -147,13 +147,16 @@ module Sidekiq
|
|
147
147
|
# As we run more processes, the scheduling interval average will approach an even spread
|
148
148
|
# between 0 and poll interval so we don't need this artifical boost.
|
149
149
|
#
|
150
|
-
|
150
|
+
count = process_count
|
151
|
+
interval = poll_interval_average(count)
|
152
|
+
|
153
|
+
if count < 10
|
151
154
|
# For small clusters, calculate a random interval that is ±50% the desired average.
|
152
|
-
|
155
|
+
interval * rand + interval.to_f / 2
|
153
156
|
else
|
154
157
|
# With 10+ processes, we should have enough randomness to get decent polling
|
155
158
|
# across the entire timespan
|
156
|
-
|
159
|
+
interval * rand
|
157
160
|
end
|
158
161
|
end
|
159
162
|
|
@@ -170,38 +173,64 @@ module Sidekiq
|
|
170
173
|
# the same time: the thundering herd problem.
|
171
174
|
#
|
172
175
|
# We only do this if poll_interval_average is unset (the default).
|
173
|
-
def poll_interval_average
|
174
|
-
|
176
|
+
def poll_interval_average(count)
|
177
|
+
@config[:poll_interval_average] || scaled_poll_interval(count)
|
175
178
|
end
|
176
179
|
|
177
180
|
# Calculates an average poll interval based on the number of known Sidekiq processes.
|
178
181
|
# This minimizes a single point of failure by dispersing check-ins but without taxing
|
179
182
|
# Redis if you run many Sidekiq processes.
|
180
|
-
def scaled_poll_interval
|
181
|
-
process_count *
|
183
|
+
def scaled_poll_interval(process_count)
|
184
|
+
process_count * @config[:average_scheduled_poll_interval]
|
182
185
|
end
|
183
186
|
|
184
187
|
def process_count
|
185
|
-
|
186
|
-
# expensive at scale. Cut it down by 90% with this counter.
|
187
|
-
# NB: This method is only called by the scheduler thread so we
|
188
|
-
# don't need to worry about the thread safety of +=.
|
189
|
-
pcount = Sidekiq::ProcessSet.new(@count_calls % 10 == 0).size
|
188
|
+
pcount = Sidekiq.redis { |conn| conn.scard("processes") }
|
190
189
|
pcount = 1 if pcount == 0
|
191
|
-
@count_calls += 1
|
192
190
|
pcount
|
193
191
|
end
|
194
192
|
|
193
|
+
# A copy of Sidekiq::ProcessSet#cleanup because server
|
194
|
+
# should never depend on sidekiq/api.
|
195
|
+
def cleanup
|
196
|
+
# dont run cleanup more than once per minute
|
197
|
+
return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
|
198
|
+
|
199
|
+
count = 0
|
200
|
+
Sidekiq.redis do |conn|
|
201
|
+
procs = conn.sscan_each("processes").to_a
|
202
|
+
heartbeats = conn.pipelined { |pipeline|
|
203
|
+
procs.each do |key|
|
204
|
+
pipeline.hget(key, "info")
|
205
|
+
end
|
206
|
+
}
|
207
|
+
|
208
|
+
# the hash named key has an expiry of 60 seconds.
|
209
|
+
# if it's not found, that means the process has not reported
|
210
|
+
# in to Redis and probably died.
|
211
|
+
to_prune = procs.select.with_index { |proc, i|
|
212
|
+
heartbeats[i].nil?
|
213
|
+
}
|
214
|
+
count = conn.srem("processes", to_prune) unless to_prune.empty?
|
215
|
+
end
|
216
|
+
count
|
217
|
+
end
|
218
|
+
|
195
219
|
def initial_wait
|
196
|
-
# Have all processes sleep between 5-15 seconds.
|
197
|
-
#
|
220
|
+
# Have all processes sleep between 5-15 seconds. 10 seconds to give time for
|
221
|
+
# the heartbeat to register (if the poll interval is going to be calculated by the number
|
198
222
|
# of workers), and 5 random seconds to ensure they don't all hit Redis at the same time.
|
199
223
|
total = 0
|
200
|
-
total += INITIAL_WAIT unless
|
224
|
+
total += INITIAL_WAIT unless @config[:poll_interval_average]
|
201
225
|
total += (5 * rand)
|
202
226
|
|
203
227
|
@sleeper.pop(total)
|
204
228
|
rescue Timeout::Error
|
229
|
+
ensure
|
230
|
+
# periodically clean out the `processes` set in Redis which can collect
|
231
|
+
# references to dead processes over time. The process count affects how
|
232
|
+
# often we scan for scheduled jobs.
|
233
|
+
cleanup
|
205
234
|
end
|
206
235
|
end
|
207
236
|
end
|
data/lib/sidekiq/testing.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "sidekiq/client"
|
5
|
+
|
6
|
+
module Sidekiq
|
7
|
+
class TransactionAwareClient
|
8
|
+
def initialize(redis_pool)
|
9
|
+
@redis_client = Client.new(redis_pool)
|
10
|
+
end
|
11
|
+
|
12
|
+
def push(item)
|
13
|
+
# pre-allocate the JID so we can return it immediately and
|
14
|
+
# save it to the database as part of the transaction.
|
15
|
+
item["jid"] ||= SecureRandom.hex(12)
|
16
|
+
AfterCommitEverywhere.after_commit { @redis_client.push(item) }
|
17
|
+
item["jid"]
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# We don't provide transactionality for push_bulk because we don't want
|
22
|
+
# to hold potentially hundreds of thousands of job records in memory due to
|
23
|
+
# a long running enqueue process.
|
24
|
+
def push_bulk(items)
|
25
|
+
@redis_client.push_bulk(items)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
|
32
|
+
module Sidekiq
|
33
|
+
def self.transactional_push!
|
34
|
+
begin
|
35
|
+
require "after_commit_everywhere"
|
36
|
+
rescue LoadError
|
37
|
+
Sidekiq.logger.error("You need to add after_commit_everywhere to your Gemfile to use Sidekiq's transactional client")
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
|
41
|
+
default_job_options["client_class"] = Sidekiq::TransactionAwareClient
|
42
|
+
Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -15,11 +15,11 @@ module Sidekiq
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def halt(res)
|
18
|
-
throw :halt, [res, {"
|
18
|
+
throw :halt, [res, {"content-type" => "text/plain"}, [res.to_s]]
|
19
19
|
end
|
20
20
|
|
21
21
|
def redirect(location)
|
22
|
-
throw :halt, [302, {"
|
22
|
+
throw :halt, [302, {"location" => "#{request.base_url}#{location}"}, []]
|
23
23
|
end
|
24
24
|
|
25
25
|
def params
|
@@ -68,7 +68,7 @@ module Sidekiq
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def json(payload)
|
71
|
-
[200, {"
|
71
|
+
[200, {"content-type" => "application/json", "cache-control" => "private, no-store"}, [Sidekiq.dump_json(payload)]]
|
72
72
|
end
|
73
73
|
|
74
74
|
def initialize(env, block)
|
@@ -60,7 +60,23 @@ module Sidekiq
|
|
60
60
|
erb(:dashboard)
|
61
61
|
end
|
62
62
|
|
63
|
+
get "/metrics" do
|
64
|
+
q = Sidekiq::Metrics::Query.new
|
65
|
+
@query_result = q.top_jobs
|
66
|
+
erb(:metrics)
|
67
|
+
end
|
68
|
+
|
69
|
+
get "/metrics/:name" do
|
70
|
+
@name = route_params[:name]
|
71
|
+
q = Sidekiq::Metrics::Query.new
|
72
|
+
@query_result = q.for_job(@name)
|
73
|
+
erb(:metrics_for_job)
|
74
|
+
end
|
75
|
+
|
63
76
|
get "/busy" do
|
77
|
+
@count = (params["count"] || 100).to_i
|
78
|
+
(@current_page, @total_size, @workset) = page_items(workset, params["page"], @count)
|
79
|
+
|
64
80
|
erb(:busy)
|
65
81
|
end
|
66
82
|
|
@@ -299,7 +315,7 @@ module Sidekiq
|
|
299
315
|
|
300
316
|
def call(env)
|
301
317
|
action = self.class.match(env)
|
302
|
-
return [404, {"
|
318
|
+
return [404, {"content-type" => "text/plain", "x-cascade" => "pass"}, ["Not Found"]] unless action
|
303
319
|
|
304
320
|
app = @klass
|
305
321
|
resp = catch(:halt) do
|
@@ -316,10 +332,10 @@ module Sidekiq
|
|
316
332
|
else
|
317
333
|
# rendered content goes here
|
318
334
|
headers = {
|
319
|
-
"
|
320
|
-
"
|
321
|
-
"
|
322
|
-
"
|
335
|
+
"content-type" => "text/html",
|
336
|
+
"cache-control" => "private, no-store",
|
337
|
+
"content-language" => action.locale,
|
338
|
+
"content-security-policy" => CSP_HEADER
|
323
339
|
}
|
324
340
|
# we'll let Rack calculate Content-Length for us.
|
325
341
|
[200, headers, [resp]]
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -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.
|
18
|
+
strs = YAML.safe_load(File.open(file))
|
19
19
|
global.merge!(strs[lang])
|
20
20
|
end
|
21
21
|
end
|
@@ -137,7 +137,7 @@ module Sidekiq
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def sort_direction_label
|
140
|
-
params[:direction] == "asc" ? "↑" : "↓"
|
140
|
+
(params[:direction] == "asc") ? "↑" : "↓"
|
141
141
|
end
|
142
142
|
|
143
143
|
def workset
|
@@ -148,6 +148,19 @@ module Sidekiq
|
|
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
|
@@ -175,7 +188,7 @@ module Sidekiq
|
|
175
188
|
end
|
176
189
|
|
177
190
|
def current_status
|
178
|
-
workset.size == 0 ? "idle" : "active"
|
191
|
+
(workset.size == 0) ? "idle" : "active"
|
179
192
|
end
|
180
193
|
|
181
194
|
def relative_time(time)
|
@@ -208,7 +221,7 @@ module Sidekiq
|
|
208
221
|
end
|
209
222
|
|
210
223
|
def truncate(text, truncate_after_chars = 2000)
|
211
|
-
truncate_after_chars && text.size > truncate_after_chars ? "#{text[0..truncate_after_chars]}..." : text
|
224
|
+
(truncate_after_chars && text.size > truncate_after_chars) ? "#{text[0..truncate_after_chars]}..." : text
|
212
225
|
end
|
213
226
|
|
214
227
|
def display_args(args, truncate_after_chars = 2000)
|
@@ -301,7 +314,7 @@ module Sidekiq
|
|
301
314
|
end
|
302
315
|
|
303
316
|
def environment_title_prefix
|
304
|
-
environment = Sidekiq
|
317
|
+
environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
305
318
|
|
306
319
|
"[#{environment.upcase}] " unless environment == "production"
|
307
320
|
end
|
data/lib/sidekiq/web.rb
CHANGED
@@ -33,6 +33,10 @@ module Sidekiq
|
|
33
33
|
"Dead" => "morgue"
|
34
34
|
}
|
35
35
|
|
36
|
+
if ENV["SIDEKIQ_METRICS_BETA"] == "1"
|
37
|
+
DEFAULT_TABS["Metrics"] = "metrics"
|
38
|
+
end
|
39
|
+
|
36
40
|
class << self
|
37
41
|
def settings
|
38
42
|
self
|
@@ -144,7 +148,7 @@ module Sidekiq
|
|
144
148
|
m = middlewares
|
145
149
|
|
146
150
|
rules = []
|
147
|
-
rules = [[:all, {"
|
151
|
+
rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
148
152
|
|
149
153
|
::Rack::Builder.new do
|
150
154
|
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
data/lib/sidekiq/worker.rb
CHANGED
@@ -257,7 +257,7 @@ module Sidekiq
|
|
257
257
|
def at(interval)
|
258
258
|
int = interval.to_f
|
259
259
|
now = Time.now.to_f
|
260
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
260
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
261
261
|
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
262
262
|
@opts["at"] = ts if ts > now
|
263
263
|
self
|
@@ -324,7 +324,7 @@ module Sidekiq
|
|
324
324
|
def perform_in(interval, *args)
|
325
325
|
int = interval.to_f
|
326
326
|
now = Time.now.to_f
|
327
|
-
ts = (int < 1_000_000_000 ? now + int : int)
|
327
|
+
ts = ((int < 1_000_000_000) ? now + int : int)
|
328
328
|
|
329
329
|
item = {"class" => self, "args" => args}
|
330
330
|
|
@@ -340,7 +340,7 @@ module Sidekiq
|
|
340
340
|
# Legal options:
|
341
341
|
#
|
342
342
|
# queue - use a named queue for this Worker, default 'default'
|
343
|
-
# retry - enable
|
343
|
+
# retry - enable retries via JobRetry, *true* to use the default
|
344
344
|
# or *Integer* count
|
345
345
|
# backtrace - whether to save any error backtrace in the retry payload to display in web UI,
|
346
346
|
# can be true, false or an integer number of lines to save, default *false*
|
@@ -348,6 +348,9 @@ module Sidekiq
|
|
348
348
|
#
|
349
349
|
# In practice, any option is allowed. This is the main mechanism to configure the
|
350
350
|
# options for a specific job.
|
351
|
+
#
|
352
|
+
# These options will be saved into the serialized job when enqueued by
|
353
|
+
# the client.
|
351
354
|
def sidekiq_options(opts = {})
|
352
355
|
super
|
353
356
|
end
|
@@ -359,7 +362,8 @@ module Sidekiq
|
|
359
362
|
|
360
363
|
def build_client # :nodoc:
|
361
364
|
pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
|
362
|
-
Sidekiq::Client
|
365
|
+
client_class = get_sidekiq_options["client_class"] || Sidekiq::Client
|
366
|
+
client_class.new(pool)
|
363
367
|
end
|
364
368
|
end
|
365
369
|
end
|