sidekiq 4.1.1 → 4.2.0
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.
- checksums.yaml +4 -4
- data/.github/issue_template.md +4 -0
- data/.travis.yml +3 -6
- data/4.0-Upgrade.md +3 -0
- data/COMM-LICENSE +1 -1
- data/Changes.md +69 -0
- data/Ent-Changes.md +40 -0
- data/Gemfile +6 -5
- data/Pro-3.0-Upgrade.md +5 -7
- data/Pro-Changes.md +66 -0
- data/README.md +2 -1
- data/bin/sidekiqload +2 -2
- data/lib/sidekiq.rb +5 -1
- data/lib/sidekiq/api.rb +3 -1
- data/lib/sidekiq/cli.rb +15 -2
- data/lib/sidekiq/client.rb +11 -3
- data/lib/sidekiq/core_ext.rb +1 -0
- data/lib/sidekiq/exception_handler.rb +2 -1
- data/lib/sidekiq/extensions/action_mailer.rb +1 -0
- data/lib/sidekiq/extensions/active_record.rb +1 -0
- data/lib/sidekiq/extensions/class_methods.rb +1 -0
- data/lib/sidekiq/extensions/generic_proxy.rb +1 -0
- data/lib/sidekiq/fetch.rb +1 -0
- data/lib/sidekiq/launcher.rb +9 -3
- data/lib/sidekiq/logging.rb +2 -1
- data/lib/sidekiq/manager.rb +2 -0
- data/lib/sidekiq/middleware/chain.rb +1 -0
- data/lib/sidekiq/middleware/i18n.rb +1 -0
- data/lib/sidekiq/middleware/server/retry_jobs.rb +7 -7
- data/lib/sidekiq/paginator.rb +1 -0
- data/lib/sidekiq/processor.rb +29 -25
- data/lib/sidekiq/rails.rb +18 -0
- data/lib/sidekiq/redis_connection.rb +6 -3
- data/lib/sidekiq/scheduled.rb +2 -0
- data/lib/sidekiq/testing.rb +1 -0
- data/lib/sidekiq/testing/inline.rb +1 -0
- data/lib/sidekiq/util.rb +1 -0
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web.rb +80 -202
- data/lib/sidekiq/web/action.rb +99 -0
- data/lib/sidekiq/web/application.rb +335 -0
- data/lib/sidekiq/{web_helpers.rb → web/helpers.rb} +31 -11
- data/lib/sidekiq/web/router.rb +96 -0
- data/lib/sidekiq/worker.rb +1 -0
- data/sidekiq.gemspec +2 -2
- data/test/fake_env.rb +1 -0
- data/test/helper.rb +1 -0
- data/test/test_actors.rb +1 -0
- data/test/test_api.rb +1 -0
- data/test/test_cli.rb +15 -2
- data/test/test_client.rb +34 -0
- data/test/test_exception_handler.rb +2 -1
- data/test/test_extensions.rb +1 -0
- data/test/test_fetch.rb +1 -0
- data/test/test_launcher.rb +17 -2
- data/test/test_logging.rb +1 -0
- data/test/test_manager.rb +1 -0
- data/test/test_middleware.rb +1 -0
- data/test/test_processor.rb +1 -0
- data/test/test_rails.rb +1 -0
- data/test/test_redis_connection.rb +7 -1
- data/test/test_retry.rb +1 -0
- data/test/test_scheduled.rb +1 -0
- data/test/test_scheduling.rb +1 -0
- data/test/test_sidekiq.rb +1 -0
- data/test/test_testing.rb +1 -0
- data/test/test_testing_fake.rb +1 -0
- data/test/test_testing_inline.rb +2 -1
- data/test/test_util.rb +1 -0
- data/test/test_web.rb +53 -5
- data/test/test_web_helpers.rb +1 -0
- data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
- data/web/assets/javascripts/application.js +5 -0
- data/web/assets/javascripts/locales/{jquery.timeago.no.js → jquery.timeago.nb.js} +1 -1
- data/web/assets/stylesheets/application.css +26 -1
- data/web/assets/stylesheets/bootstrap.css +4 -8
- data/web/locales/de.yml +1 -1
- data/web/locales/en.yml +1 -0
- data/web/locales/ru.yml +3 -0
- data/web/views/_footer.erb +1 -1
- data/web/views/_nav.erb +1 -1
- data/web/views/busy.erb +4 -4
- data/web/views/dashboard.erb +2 -2
- data/web/views/dead.erb +1 -1
- data/web/views/layout.erb +3 -3
- data/web/views/morgue.erb +2 -2
- data/web/views/queue.erb +3 -3
- data/web/views/queues.erb +1 -1
- data/web/views/retries.erb +2 -2
- data/web/views/retry.erb +1 -1
- data/web/views/scheduled.erb +2 -2
- data/web/views/scheduled_job_info.erb +1 -1
- metadata +17 -29
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/views/_poll_js.erb +0 -5
data/lib/sidekiq/core_ext.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sidekiq'
|
2
3
|
|
3
4
|
module Sidekiq
|
@@ -5,7 +6,7 @@ module Sidekiq
|
|
5
6
|
|
6
7
|
class Logger
|
7
8
|
def call(ex, ctxHash)
|
8
|
-
Sidekiq.logger.warn(ctxHash) if !ctxHash.empty?
|
9
|
+
Sidekiq.logger.warn(Sidekiq.dump_json(ctxHash)) if !ctxHash.empty?
|
9
10
|
Sidekiq.logger.warn "#{ex.class.name}: #{ex.message}"
|
10
11
|
Sidekiq.logger.warn ex.backtrace.join("\n") unless ex.backtrace.nil?
|
11
12
|
end
|
data/lib/sidekiq/fetch.rb
CHANGED
data/lib/sidekiq/launcher.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# encoding: utf-8
|
2
3
|
require 'sidekiq/manager'
|
3
4
|
require 'sidekiq/fetch'
|
@@ -79,7 +80,7 @@ module Sidekiq
|
|
79
80
|
workers_key = "#{key}:workers".freeze
|
80
81
|
nowdate = Time.now.utc.strftime("%Y-%m-%d".freeze)
|
81
82
|
Sidekiq.redis do |conn|
|
82
|
-
conn.
|
83
|
+
conn.multi do
|
83
84
|
conn.incrby("stat:processed".freeze, procd)
|
84
85
|
conn.incrby("stat:processed:#{nowdate}", procd)
|
85
86
|
conn.incrby("stat:failed".freeze, fails)
|
@@ -88,19 +89,24 @@ module Sidekiq
|
|
88
89
|
Processor::WORKER_STATE.each_pair do |tid, hash|
|
89
90
|
conn.hset(workers_key, tid, Sidekiq.dump_json(hash))
|
90
91
|
end
|
92
|
+
conn.expire(workers_key, 60)
|
91
93
|
end
|
92
94
|
end
|
93
95
|
fails = procd = 0
|
94
96
|
|
95
|
-
_, _, _, msg = Sidekiq.redis do |conn|
|
96
|
-
conn.
|
97
|
+
_, exists, _, _, msg = Sidekiq.redis do |conn|
|
98
|
+
conn.multi do
|
97
99
|
conn.sadd('processes', key)
|
100
|
+
conn.exists(key)
|
98
101
|
conn.hmset(key, 'info', json, 'busy', Processor::WORKER_STATE.size, 'beat', Time.now.to_f, 'quiet', @done)
|
99
102
|
conn.expire(key, 60)
|
100
103
|
conn.rpop("#{key}-signals")
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
107
|
+
# first heartbeat or recovering from an outage and need to reestablish our heartbeat
|
108
|
+
fire_event(:heartbeat) if !exists
|
109
|
+
|
104
110
|
return unless msg
|
105
111
|
|
106
112
|
if JVM_RESERVED_SIGNALS.include?(msg)
|
data/lib/sidekiq/logging.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'time'
|
2
3
|
require 'logger'
|
3
4
|
require 'fcntl'
|
@@ -47,7 +48,7 @@ module Sidekiq
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def self.logger=(log)
|
50
|
-
@logger = (log ? log : Logger.new(
|
51
|
+
@logger = (log ? log : Logger.new(File::NULL))
|
51
52
|
end
|
52
53
|
|
53
54
|
# This reopens ALL logfiles in the process that have been rotated
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -8,14 +8,14 @@ module Sidekiq
|
|
8
8
|
# Automatically retry jobs that fail in Sidekiq.
|
9
9
|
# Sidekiq's retry support assumes a typical development lifecycle:
|
10
10
|
#
|
11
|
-
# 0.
|
12
|
-
# 1.
|
13
|
-
# the job and pushes it onto a retry queue
|
14
|
-
# 2.
|
15
|
-
# an exponential delay, the job continues to fail
|
16
|
-
# 3.
|
11
|
+
# 0. Push some code changes with a bug in it.
|
12
|
+
# 1. Bug causes job processing to fail, Sidekiq's middleware captures
|
13
|
+
# the job and pushes it onto a retry queue.
|
14
|
+
# 2. Sidekiq retries jobs in the retry queue multiple times with
|
15
|
+
# an exponential delay, the job continues to fail.
|
16
|
+
# 3. After a few days, a developer deploys a fix. The job is
|
17
17
|
# reprocessed successfully.
|
18
|
-
# 4.
|
18
|
+
# 4. Once retries are exhausted, Sidekiq will give up and move the
|
19
19
|
# job to the Dead Job Queue (aka morgue) where it must be dealt with
|
20
20
|
# manually in the Web UI.
|
21
21
|
# 5. After 6 months on the DJQ, Sidekiq will discard the job.
|
data/lib/sidekiq/paginator.rb
CHANGED
data/lib/sidekiq/processor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sidekiq/util'
|
2
3
|
require 'sidekiq/fetch'
|
3
4
|
require 'thread'
|
@@ -35,6 +36,7 @@ module Sidekiq
|
|
35
36
|
@job = nil
|
36
37
|
@thread = nil
|
37
38
|
@strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
|
39
|
+
@reloader = Sidekiq.options[:reloader]
|
38
40
|
end
|
39
41
|
|
40
42
|
def terminate(wait=false)
|
@@ -117,33 +119,35 @@ module Sidekiq
|
|
117
119
|
jobstr = work.job
|
118
120
|
queue = work.queue_name
|
119
121
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
122
|
+
@reloader.call do
|
123
|
+
ack = false
|
124
|
+
begin
|
125
|
+
job = Sidekiq.load_json(jobstr)
|
126
|
+
klass = job['class'.freeze].constantize
|
127
|
+
worker = klass.new
|
128
|
+
worker.jid = job['jid'.freeze]
|
129
|
+
|
130
|
+
stats(worker, job, queue) do
|
131
|
+
Sidekiq.server_middleware.invoke(worker, job, queue) do
|
132
|
+
# Only ack if we either attempted to start this job or
|
133
|
+
# successfully completed it. This prevents us from
|
134
|
+
# losing jobs if a middleware raises an exception before yielding
|
135
|
+
ack = true
|
136
|
+
execute_job(worker, cloned(job['args'.freeze]))
|
137
|
+
end
|
134
138
|
end
|
139
|
+
ack = true
|
140
|
+
rescue Sidekiq::Shutdown
|
141
|
+
# Had to force kill this job because it didn't finish
|
142
|
+
# within the timeout. Don't acknowledge the work since
|
143
|
+
# we didn't properly finish it.
|
144
|
+
ack = false
|
145
|
+
rescue Exception => ex
|
146
|
+
handle_exception(ex, job || { :job => jobstr })
|
147
|
+
raise
|
148
|
+
ensure
|
149
|
+
work.acknowledge if ack
|
135
150
|
end
|
136
|
-
ack = true
|
137
|
-
rescue Sidekiq::Shutdown
|
138
|
-
# Had to force kill this job because it didn't finish
|
139
|
-
# within the timeout. Don't acknowledge the work since
|
140
|
-
# we didn't properly finish it.
|
141
|
-
ack = false
|
142
|
-
rescue Exception => ex
|
143
|
-
handle_exception(ex, job || { :job => jobstr })
|
144
|
-
raise
|
145
|
-
ensure
|
146
|
-
work.acknowledge if ack
|
147
151
|
end
|
148
152
|
end
|
149
153
|
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sidekiq
|
2
3
|
def self.hook_rails!
|
3
4
|
return if defined?(@delay_removed)
|
@@ -34,5 +35,22 @@ module Sidekiq
|
|
34
35
|
initializer 'sidekiq' do
|
35
36
|
Sidekiq.hook_rails!
|
36
37
|
end
|
38
|
+
|
39
|
+
class Reloader
|
40
|
+
def initialize(app = ::Rails.application)
|
41
|
+
Sidekiq.logger.debug "Enabling Rails 5+ live code reloading, so hot!" unless app.config.cache_classes
|
42
|
+
@app = app
|
43
|
+
end
|
44
|
+
|
45
|
+
def call
|
46
|
+
@app.reloader.wrap do
|
47
|
+
yield
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
|
53
|
+
end
|
54
|
+
end
|
37
55
|
end if defined?(::Rails)
|
38
56
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'connection_pool'
|
2
3
|
require 'redis'
|
3
4
|
require 'uri'
|
@@ -7,6 +8,8 @@ module Sidekiq
|
|
7
8
|
class << self
|
8
9
|
|
9
10
|
def create(options={})
|
11
|
+
options = options.symbolize_keys
|
12
|
+
|
10
13
|
options[:url] ||= determine_redis_provider
|
11
14
|
|
12
15
|
size = options[:size] || (Sidekiq.server? ? (Sidekiq.options[:concurrency] + 5) : 5)
|
@@ -32,7 +35,7 @@ module Sidekiq
|
|
32
35
|
# - enterprise's leader election
|
33
36
|
# - enterprise's cron support
|
34
37
|
def verify_sizing(size, concurrency)
|
35
|
-
raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work
|
38
|
+
raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work. Your pool has #{size} connections but really needs to have at least #{concurrency + 2}" if size <= concurrency
|
36
39
|
end
|
37
40
|
|
38
41
|
def build_client(options)
|
@@ -44,8 +47,8 @@ module Sidekiq
|
|
44
47
|
require 'redis/namespace'
|
45
48
|
Redis::Namespace.new(namespace, :redis => client)
|
46
49
|
rescue LoadError
|
47
|
-
Sidekiq.logger.error("Your Redis configuration
|
48
|
-
"Add the gem to your Gemfile
|
50
|
+
Sidekiq.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \
|
51
|
+
"Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.")
|
49
52
|
exit(-127)
|
50
53
|
end
|
51
54
|
else
|
data/lib/sidekiq/scheduled.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sidekiq'
|
2
3
|
require 'sidekiq/util'
|
3
4
|
require 'sidekiq/api'
|
@@ -45,6 +46,7 @@ module Sidekiq
|
|
45
46
|
@enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
|
46
47
|
@sleeper = ConnectionPool::TimedStack.new
|
47
48
|
@done = false
|
49
|
+
@thread = nil
|
48
50
|
end
|
49
51
|
|
50
52
|
# Shut down this instance, will pause until the thread is dead.
|
data/lib/sidekiq/testing.rb
CHANGED
data/lib/sidekiq/util.rb
CHANGED
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
@@ -1,25 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'erb'
|
2
|
-
require 'yaml'
|
3
|
-
require 'sinatra/base'
|
4
3
|
|
5
4
|
require 'sidekiq'
|
6
5
|
require 'sidekiq/api'
|
7
6
|
require 'sidekiq/paginator'
|
8
|
-
require 'sidekiq/
|
7
|
+
require 'sidekiq/web/helpers'
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
require 'sidekiq/web/router'
|
10
|
+
require 'sidekiq/web/action'
|
11
|
+
require 'sidekiq/web/application'
|
13
12
|
|
14
|
-
|
15
|
-
use ::Rack::Protection, :use => :authenticity_token unless ENV['RACK_ENV'] == 'test'
|
13
|
+
require 'rack/protection'
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
set :locales, ["#{root}/locales"]
|
15
|
+
require 'rack/builder'
|
16
|
+
require 'rack/file'
|
17
|
+
require 'rack/session/cookie'
|
21
18
|
|
22
|
-
|
19
|
+
module Sidekiq
|
20
|
+
class Web
|
21
|
+
ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../web")
|
22
|
+
VIEWS = "#{ROOT}/views".freeze
|
23
|
+
LOCALES = ["#{ROOT}/locales".freeze]
|
24
|
+
LAYOUT = "#{VIEWS}/layout.erb".freeze
|
25
|
+
ASSETS = "#{ROOT}/assets".freeze
|
23
26
|
|
24
27
|
DEFAULT_TABS = {
|
25
28
|
"Dashboard" => '',
|
@@ -31,6 +34,18 @@ module Sidekiq
|
|
31
34
|
}
|
32
35
|
|
33
36
|
class << self
|
37
|
+
def settings
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def middlewares
|
42
|
+
@middlewares ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def use(*middleware_args, &block)
|
46
|
+
middlewares << [middleware_args, block]
|
47
|
+
end
|
48
|
+
|
34
49
|
def default_tabs
|
35
50
|
DEFAULT_TABS
|
36
51
|
end
|
@@ -40,234 +55,97 @@ module Sidekiq
|
|
40
55
|
end
|
41
56
|
alias_method :tabs, :custom_tabs
|
42
57
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
get "/busy" do
|
47
|
-
erb :busy
|
48
|
-
end
|
49
|
-
|
50
|
-
post "/busy" do
|
51
|
-
if params['identity']
|
52
|
-
p = Sidekiq::Process.new('identity' => params['identity'])
|
53
|
-
p.quiet! if params[:quiet]
|
54
|
-
p.stop! if params[:stop]
|
55
|
-
else
|
56
|
-
processes.each do |pro|
|
57
|
-
pro.quiet! if params[:quiet]
|
58
|
-
pro.stop! if params[:stop]
|
59
|
-
end
|
58
|
+
def locales
|
59
|
+
@locales ||= LOCALES
|
60
60
|
end
|
61
|
-
redirect "#{root_path}busy"
|
62
|
-
end
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
erb :queues
|
67
|
-
end
|
68
|
-
|
69
|
-
get "/queues/:name" do
|
70
|
-
halt 404 unless params[:name]
|
71
|
-
@count = (params[:count] || 25).to_i
|
72
|
-
@name = params[:name]
|
73
|
-
@queue = Sidekiq::Queue.new(@name)
|
74
|
-
(@current_page, @total_size, @messages) = page("queue:#{@name}", params[:page], @count)
|
75
|
-
@messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
|
76
|
-
erb :queue
|
77
|
-
end
|
78
|
-
|
79
|
-
post "/queues/:name" do
|
80
|
-
Sidekiq::Queue.new(params[:name]).clear
|
81
|
-
redirect "#{root_path}queues"
|
82
|
-
end
|
83
|
-
|
84
|
-
post "/queues/:name/delete" do
|
85
|
-
Sidekiq::Job.new(params[:key_val], params[:name]).delete
|
86
|
-
redirect_with_query("#{root_path}queues/#{params[:name]}")
|
87
|
-
end
|
88
|
-
|
89
|
-
get '/morgue' do
|
90
|
-
@count = (params[:count] || 25).to_i
|
91
|
-
(@current_page, @total_size, @dead) = page("dead", params[:page], @count, reverse: true)
|
92
|
-
@dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
93
|
-
erb :morgue
|
94
|
-
end
|
95
|
-
|
96
|
-
get "/morgue/:key" do
|
97
|
-
halt 404 unless params['key']
|
98
|
-
@dead = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
|
99
|
-
redirect "#{root_path}morgue" if @dead.nil?
|
100
|
-
erb :dead
|
101
|
-
end
|
102
|
-
|
103
|
-
post '/morgue' do
|
104
|
-
redirect request.path unless params['key']
|
105
|
-
|
106
|
-
params['key'].each do |key|
|
107
|
-
job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
|
108
|
-
retry_or_delete_or_kill job, params if job
|
62
|
+
def views
|
63
|
+
@views ||= VIEWS
|
109
64
|
end
|
110
|
-
redirect_with_query("#{root_path}morgue")
|
111
|
-
end
|
112
65
|
|
113
|
-
|
114
|
-
|
115
|
-
redirect "#{root_path}morgue"
|
66
|
+
attr_accessor :app_url, :session_secret, :redis_pool
|
67
|
+
attr_writer :locales, :views
|
116
68
|
end
|
117
69
|
|
118
|
-
|
119
|
-
|
120
|
-
redirect "#{root_path}morgue"
|
70
|
+
def settings
|
71
|
+
self.class.settings
|
121
72
|
end
|
122
73
|
|
123
|
-
|
124
|
-
|
125
|
-
job = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
|
126
|
-
retry_or_delete_or_kill job, params if job
|
127
|
-
redirect_with_query("#{root_path}morgue")
|
74
|
+
def use(*middleware_args, &block)
|
75
|
+
middlewares << [middleware_args, block]
|
128
76
|
end
|
129
77
|
|
130
|
-
|
131
|
-
|
132
|
-
@count = (params[:count] || 25).to_i
|
133
|
-
(@current_page, @total_size, @retries) = page("retry", params[:page], @count)
|
134
|
-
@retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
135
|
-
erb :retries
|
136
|
-
end
|
137
|
-
|
138
|
-
get "/retries/:key" do
|
139
|
-
@retry = Sidekiq::RetrySet.new.fetch(*parse_params(params['key'])).first
|
140
|
-
redirect "#{root_path}retries" if @retry.nil?
|
141
|
-
erb :retry
|
142
|
-
end
|
143
|
-
|
144
|
-
post '/retries' do
|
145
|
-
redirect request.path unless params['key']
|
146
|
-
|
147
|
-
params['key'].each do |key|
|
148
|
-
job = Sidekiq::RetrySet.new.fetch(*parse_params(key)).first
|
149
|
-
retry_or_delete_or_kill job, params if job
|
150
|
-
end
|
151
|
-
redirect_with_query("#{root_path}retries")
|
78
|
+
def middlewares
|
79
|
+
@middlewares ||= Web.middlewares.dup
|
152
80
|
end
|
153
81
|
|
154
|
-
|
155
|
-
|
156
|
-
redirect "#{root_path}retries"
|
82
|
+
def call(env)
|
83
|
+
app.call(env)
|
157
84
|
end
|
158
85
|
|
159
|
-
|
160
|
-
|
161
|
-
|
86
|
+
def self.call(env)
|
87
|
+
@app ||= new
|
88
|
+
@app.call(env)
|
162
89
|
end
|
163
90
|
|
164
|
-
|
165
|
-
|
166
|
-
retry_or_delete_or_kill job, params if job
|
167
|
-
redirect_with_query("#{root_path}retries")
|
91
|
+
def app
|
92
|
+
@app ||= build
|
168
93
|
end
|
169
94
|
|
170
|
-
|
171
|
-
|
172
|
-
(@current_page, @total_size, @scheduled) = page("schedule", params[:page], @count)
|
173
|
-
@scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
174
|
-
erb :scheduled
|
95
|
+
def self.register(extension)
|
96
|
+
extension.registered(WebApplication)
|
175
97
|
end
|
176
98
|
|
177
|
-
|
178
|
-
@job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
|
179
|
-
redirect "#{root_path}scheduled" if @job.nil?
|
180
|
-
erb :scheduled_job_info
|
181
|
-
end
|
182
|
-
|
183
|
-
post '/scheduled' do
|
184
|
-
redirect request.path unless params['key']
|
99
|
+
private
|
185
100
|
|
186
|
-
|
187
|
-
|
188
|
-
|
101
|
+
def using?(middleware)
|
102
|
+
middlewares.any? do |(m,_)|
|
103
|
+
m.kind_of?(Array) && (m[0] == middleware || m[0].kind_of?(middleware))
|
189
104
|
end
|
190
|
-
redirect_with_query("#{root_path}scheduled")
|
191
|
-
end
|
192
|
-
|
193
|
-
post "/scheduled/:key" do
|
194
|
-
halt 404 unless params['key']
|
195
|
-
job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
|
196
|
-
delete_or_add_queue job, params if job
|
197
|
-
redirect_with_query("#{root_path}scheduled")
|
198
|
-
end
|
199
|
-
|
200
|
-
get '/' do
|
201
|
-
@redis_info = redis_info.select{ |k, v| REDIS_KEYS.include? k }
|
202
|
-
stats_history = Sidekiq::Stats::History.new((params[:days] || 30).to_i)
|
203
|
-
@processed_history = stats_history.processed
|
204
|
-
@failed_history = stats_history.failed
|
205
|
-
erb :dashboard
|
206
105
|
end
|
207
106
|
|
208
|
-
|
107
|
+
def build
|
108
|
+
middlewares = self.middlewares
|
109
|
+
klass = self.class
|
209
110
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
get '/stats' do
|
215
|
-
sidekiq_stats = Sidekiq::Stats.new
|
216
|
-
redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
|
217
|
-
|
218
|
-
content_type :json
|
219
|
-
Sidekiq.dump_json(
|
220
|
-
sidekiq: {
|
221
|
-
processed: sidekiq_stats.processed,
|
222
|
-
failed: sidekiq_stats.failed,
|
223
|
-
busy: sidekiq_stats.workers_size,
|
224
|
-
processes: sidekiq_stats.processes_size,
|
225
|
-
enqueued: sidekiq_stats.enqueued,
|
226
|
-
scheduled: sidekiq_stats.scheduled_size,
|
227
|
-
retries: sidekiq_stats.retry_size,
|
228
|
-
dead: sidekiq_stats.dead_size,
|
229
|
-
default_latency: sidekiq_stats.default_queue_latency
|
230
|
-
},
|
231
|
-
redis: redis_stats
|
232
|
-
)
|
233
|
-
end
|
111
|
+
unless using?(::Rack::Protection) || ENV['RACK_ENV'] == 'test'
|
112
|
+
middlewares.unshift [[::Rack::Protection, { use: :authenticity_token }], nil]
|
113
|
+
end
|
234
114
|
|
235
|
-
|
236
|
-
|
115
|
+
unless using? ::Rack::Session::Cookie
|
116
|
+
unless secret = Web.session_secret
|
117
|
+
require 'securerandom'
|
118
|
+
secret = SecureRandom.hex(64)
|
119
|
+
end
|
237
120
|
|
238
|
-
|
239
|
-
|
240
|
-
queue_stats.lengths
|
241
|
-
)
|
242
|
-
end
|
121
|
+
middlewares.unshift [[::Rack::Session::Cookie, { secret: secret }], nil]
|
122
|
+
end
|
243
123
|
|
244
|
-
|
124
|
+
::Rack::Builder.new do
|
125
|
+
%w(stylesheets javascripts images).each do |asset_dir|
|
126
|
+
map "/#{asset_dir}" do
|
127
|
+
run ::Rack::File.new("#{ASSETS}/#{asset_dir}", { 'Cache-Control' => 'public, max-age=86400' })
|
128
|
+
end
|
129
|
+
end
|
245
130
|
|
246
|
-
|
247
|
-
if params['retry']
|
248
|
-
job.retry
|
249
|
-
elsif params['delete']
|
250
|
-
job.delete
|
251
|
-
elsif params['kill']
|
252
|
-
job.kill
|
253
|
-
end
|
254
|
-
end
|
131
|
+
middlewares.each {|middleware, block| use(*middleware, &block) }
|
255
132
|
|
256
|
-
|
257
|
-
if params['delete']
|
258
|
-
job.delete
|
259
|
-
elsif params['add_to_queue']
|
260
|
-
job.add_to_queue
|
133
|
+
run WebApplication.new(klass)
|
261
134
|
end
|
262
135
|
end
|
263
136
|
end
|
137
|
+
|
138
|
+
Sidekiq::WebApplication.helpers WebHelpers
|
139
|
+
Sidekiq::WebApplication.helpers Sidekiq::Paginator
|
140
|
+
|
141
|
+
Sidekiq::WebAction.class_eval "def _render\n#{ERB.new(File.read(Web::LAYOUT)).src}\nend"
|
264
142
|
end
|
265
143
|
|
266
144
|
if defined?(::ActionDispatch::Request::Session) &&
|
267
145
|
!::ActionDispatch::Request::Session.respond_to?(:each)
|
268
146
|
# mperham/sidekiq#2460
|
269
147
|
# Rack apps can't reuse the Rails session store without
|
270
|
-
# this monkeypatch
|
148
|
+
# this monkeypatch, fixed in Rails 5.
|
271
149
|
class ActionDispatch::Request::Session
|
272
150
|
def each(&block)
|
273
151
|
hash = self.to_hash
|