sidekiq 4.1.4 → 4.2.0

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -6
  3. data/Changes.md +24 -0
  4. data/Ent-Changes.md +24 -1
  5. data/Gemfile +5 -5
  6. data/Pro-Changes.md +11 -0
  7. data/lib/sidekiq.rb +4 -1
  8. data/lib/sidekiq/cli.rb +11 -2
  9. data/lib/sidekiq/launcher.rb +5 -1
  10. data/lib/sidekiq/manager.rb +1 -0
  11. data/lib/sidekiq/processor.rb +28 -25
  12. data/lib/sidekiq/rails.rb +17 -0
  13. data/lib/sidekiq/scheduled.rb +1 -0
  14. data/lib/sidekiq/version.rb +1 -1
  15. data/lib/sidekiq/web.rb +79 -202
  16. data/lib/sidekiq/web/action.rb +99 -0
  17. data/lib/sidekiq/web/application.rb +335 -0
  18. data/lib/sidekiq/{web_helpers.rb → web/helpers.rb} +29 -10
  19. data/lib/sidekiq/web/router.rb +96 -0
  20. data/sidekiq.gemspec +2 -2
  21. data/test/test_cli.rb +14 -2
  22. data/test/test_launcher.rb +12 -2
  23. data/test/test_web.rb +52 -5
  24. data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
  25. data/web/assets/javascripts/application.js +5 -0
  26. data/web/assets/stylesheets/application.css +26 -1
  27. data/web/assets/stylesheets/bootstrap.css +4 -8
  28. data/web/locales/de.yml +1 -1
  29. data/web/views/_footer.erb +1 -1
  30. data/web/views/busy.erb +2 -2
  31. data/web/views/dashboard.erb +2 -2
  32. data/web/views/dead.erb +1 -1
  33. data/web/views/layout.erb +3 -3
  34. data/web/views/morgue.erb +2 -2
  35. data/web/views/queue.erb +3 -3
  36. data/web/views/queues.erb +1 -1
  37. data/web/views/retries.erb +2 -2
  38. data/web/views/retry.erb +1 -1
  39. data/web/views/scheduled.erb +2 -2
  40. data/web/views/scheduled_job_info.erb +1 -1
  41. metadata +12 -20
  42. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  43. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  44. data/web/assets/images/status/active.png +0 -0
  45. data/web/assets/images/status/idle.png +0 -0
  46. data/web/views/_poll_js.erb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4e031cb26d8dcc6ab4f404563cd0a711577e586
4
- data.tar.gz: 0a05484ed39032f71dcd2db901afec38f4c9d023
3
+ metadata.gz: db0f25c2fe7ea87588364c3eb86e3b929197139c
4
+ data.tar.gz: 8fa8c056e6c5fad50ce5d49838515aca61573458
5
5
  SHA512:
6
- metadata.gz: c807c5e398088ee6b344cdce5fa57a77d51c7206a3cc11c4aeb8bc9af186eb82c292c215facb6ae54589ed5b1d95573b74a07622bc452b7ba970d0fb49c207df
7
- data.tar.gz: a56f9815bfc2954b12a9598b6678aee7771ee949d7e886dfc6ddaacbe05f5294e008deccf063c9c39ac430f18322cbdff4468a9ebd3530a9ef8ce780b064bf7e
6
+ metadata.gz: 4a801ac5f3d70ca6e1856cb7369f557d5bb8d1c579e775f6a4f5ed97d534af2d289f884979de978f3a7cab2d1261fabeef6b7fc9e73b1684c7b1daabbd25e0e7
7
+ data.tar.gz: 37c617e0ea241fe8cea7c85e6479e2259e06f1b5bfb06ce811b2529d73adc8a09a67655dbdcaff028ba4cd3226169a79f636f813f7848d7fe8eaa084ea9d5739
@@ -7,12 +7,6 @@ before_install:
7
7
  - gem install bundler
8
8
  - gem update bundler
9
9
  rvm:
10
- - 2.0.0
11
- - 2.1.8
12
10
  - 2.2.4
13
11
  - 2.3.0
14
12
  - jruby-head
15
- - rbx-2
16
- matrix:
17
- allow_failures:
18
- - rvm: rbx-2
data/Changes.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Sidekiq Changes
2
2
 
3
+ 4.2.0
4
+ -----------
5
+
6
+ - Enable development-mode code reloading. **With Rails 5.0+, you don't need
7
+ to restart Sidekiq to pick up your Sidekiq::Worker changes anymore!** [#2457]
8
+ - **Remove Sinatra dependency**. Sidekiq's Web UI now uses Rack directly.
9
+ Thank you to Sidekiq's newest committer, **badosu**, for writing the code
10
+ and doing a lot of testing to ensure compatibility with many different
11
+ 3rd party plugins. If your Web UI works with 4.1.4 but fails with
12
+ 4.2.0, please open an issue. [#3075]
13
+ - Allow tuning of concurrency with the `RAILS_MAX_THREADS` env var. [#2985]
14
+ This is the same var used by Puma so you can tune all of your systems
15
+ the same way:
16
+ ```sh
17
+ web: RAILS_MAX_THREADS=5 bundle exec puma ...
18
+ worker: RAILS_MAX_THREADS=10 bundle exec sidekiq ...
19
+ ```
20
+ Using `-c` or `config/sidekiq.yml` overrides this setting. I recommend
21
+ adjusting your `config/database.yml` to use it too so connections are
22
+ auto-scaled:
23
+ ```yaml
24
+ pool: <%= ENV['RAILS_MAX_THREADS'] || 5 %>
25
+ ```
26
+
3
27
  4.1.4
4
28
  -----------
5
29
 
@@ -3,7 +3,30 @@ Sidekiq Enterprise Changelog
3
3
 
4
4
  Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy.
5
5
 
6
- HEAD
6
+ 1.3.2
7
+ -------------
8
+
9
+ - Upgrade encryption to use OpenSSL's more secure GCM mode. [#3060]
10
+
11
+ 1.3.1
12
+ -------------
13
+
14
+ - Fix multi-process memory monitoring on CentOS 6.x [#3063]
15
+ - Polish the new encryption feature a bit.
16
+
17
+ 1.3.0
18
+ -------------
19
+
20
+ - **BETA** [New encryption feature](https://github.com/mperham/sidekiq/wiki/Ent-Encryption)
21
+ which automatically encrypts the last argument of a Worker, aka the secret bag.
22
+
23
+ 1.2.4
24
+ -------------
25
+
26
+ - Fix issue causing some minutely jobs to execute every other minute.
27
+ - Log a warning if slow periodic processing causes us to miss a clock tick.
28
+
29
+ 1.2.3
7
30
  -------------
8
31
 
9
32
  - Periodic jobs could stop executing until process restart if Redis goes down [#3047]
data/Gemfile CHANGED
@@ -1,8 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
+ gem 'rails', '5.0.0'
4
5
  gem "hiredis"
5
- gem 'rails', '~> 4.2'
6
6
  gem 'simplecov'
7
7
  gem 'minitest'
8
8
  gem 'minitest-utils'
@@ -23,7 +23,7 @@ platforms :mri do
23
23
  gem 'ruby-prof'
24
24
  end
25
25
 
26
- platforms :jruby do
27
- gem 'jruby-openssl'
28
- gem 'activerecord-jdbcsqlite3-adapter'
29
- end
26
+ #platforms :jruby do
27
+ #gem 'jruby-openssl'
28
+ #gem 'activerecord-jdbcsqlite3-adapter'
29
+ #end
@@ -3,6 +3,17 @@ Sidekiq Pro Changelog
3
3
 
4
4
  Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy.
5
5
 
6
+ 3.3.3
7
+ ---------
8
+
9
+ - Update Web UI extension to work with Sidekiq 4.2.0's new Web UI. [#3075]
10
+
11
+ 3.3.2
12
+ ---------
13
+
14
+ - Minimize batch memory usage after success [#3083]
15
+ - Extract batch's 24 hr linger expiry to a LINGER constant so it can be tuned. [#3011]
16
+
6
17
  3.3.1
7
18
  ---------
8
19
 
@@ -28,9 +28,11 @@ module Sidekiq
28
28
  startup: [],
29
29
  quiet: [],
30
30
  shutdown: [],
31
+ heartbeat: [],
31
32
  },
32
33
  dead_max_jobs: 10_000,
33
- dead_timeout_in_seconds: 180 * 24 * 60 * 60 # 6 months
34
+ dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
35
+ reloader: proc { |&block| block.call },
34
36
  }
35
37
 
36
38
  DEFAULT_WORKER_OPTIONS = {
@@ -169,6 +171,7 @@ module Sidekiq
169
171
  def self.default_retries_exhausted=(prok)
170
172
  @default_retries_exhausted = prok
171
173
  end
174
+ @default_retries_exhausted = ->(job, ex) { }
172
175
  def self.default_retries_exhausted
173
176
  @default_retries_exhausted
174
177
  end
@@ -208,6 +208,8 @@ module Sidekiq
208
208
  opts = parse_config(cfile).merge(opts) if cfile
209
209
 
210
210
  opts[:strict] = true if opts[:strict].nil?
211
+ opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if !opts[:concurrency] && ENV["RAILS_MAX_THREADS"]
212
+ opts[:identity] = identity
211
213
 
212
214
  options.merge!(opts)
213
215
  end
@@ -227,7 +229,7 @@ module Sidekiq
227
229
  require 'sidekiq/rails'
228
230
  require File.expand_path("#{options[:require]}/config/environment.rb")
229
231
  ::Rails.application.eager_load!
230
- else
232
+ elsif ::Rails::VERSION::MAJOR == 4
231
233
  # Painful contortions, see 1791 for discussion
232
234
  require File.expand_path("#{options[:require]}/config/application.rb")
233
235
  ::Rails::Application.initializer "sidekiq.eager_load" do
@@ -235,10 +237,17 @@ module Sidekiq
235
237
  end
236
238
  require 'sidekiq/rails'
237
239
  require File.expand_path("#{options[:require]}/config/environment.rb")
240
+ else
241
+ require 'sidekiq/rails'
242
+ require File.expand_path("#{options[:require]}/config/environment.rb")
243
+ Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
238
244
  end
239
245
  options[:tag] ||= default_tag
240
246
  else
241
- require options[:require]
247
+ not_required_message = "#{options[:require]} was not required, you should use an explicit path: " +
248
+ "./#{options[:require]} or /path/to/#{options[:require]}"
249
+
250
+ require(options[:require]) || raise(ArgumentError, not_required_message)
242
251
  end
243
252
  end
244
253
 
@@ -94,15 +94,19 @@ module Sidekiq
94
94
  end
95
95
  fails = procd = 0
96
96
 
97
- _, _, _, msg = Sidekiq.redis do |conn|
97
+ _, exists, _, _, msg = Sidekiq.redis do |conn|
98
98
  conn.multi do
99
99
  conn.sadd('processes', key)
100
+ conn.exists(key)
100
101
  conn.hmset(key, 'info', json, 'busy', Processor::WORKER_STATE.size, 'beat', Time.now.to_f, 'quiet', @done)
101
102
  conn.expire(key, 60)
102
103
  conn.rpop("#{key}-signals")
103
104
  end
104
105
  end
105
106
 
107
+ # first heartbeat or recovering from an outage and need to reestablish our heartbeat
108
+ fire_event(:heartbeat) if !exists
109
+
106
110
  return unless msg
107
111
 
108
112
  if JVM_RESERVED_SIGNALS.include?(msg)
@@ -4,6 +4,7 @@ require 'sidekiq/util'
4
4
  require 'sidekiq/processor'
5
5
  require 'sidekiq/fetch'
6
6
  require 'thread'
7
+ require 'set'
7
8
 
8
9
  module Sidekiq
9
10
 
@@ -36,6 +36,7 @@ module Sidekiq
36
36
  @job = nil
37
37
  @thread = nil
38
38
  @strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
39
+ @reloader = Sidekiq.options[:reloader]
39
40
  end
40
41
 
41
42
  def terminate(wait=false)
@@ -118,33 +119,35 @@ module Sidekiq
118
119
  jobstr = work.job
119
120
  queue = work.queue_name
120
121
 
121
- ack = false
122
- begin
123
- job = Sidekiq.load_json(jobstr)
124
- klass = job['class'.freeze].constantize
125
- worker = klass.new
126
- worker.jid = job['jid'.freeze]
127
-
128
- stats(worker, job, queue) do
129
- Sidekiq.server_middleware.invoke(worker, job, queue) do
130
- # Only ack if we either attempted to start this job or
131
- # successfully completed it. This prevents us from
132
- # losing jobs if a middleware raises an exception before yielding
133
- ack = true
134
- execute_job(worker, cloned(job['args'.freeze]))
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
135
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
136
150
  end
137
- ack = true
138
- rescue Sidekiq::Shutdown
139
- # Had to force kill this job because it didn't finish
140
- # within the timeout. Don't acknowledge the work since
141
- # we didn't properly finish it.
142
- ack = false
143
- rescue Exception => ex
144
- handle_exception(ex, job || { :job => jobstr })
145
- raise
146
- ensure
147
- work.acknowledge if ack
148
151
  end
149
152
  end
150
153
 
@@ -35,5 +35,22 @@ module Sidekiq
35
35
  initializer 'sidekiq' do
36
36
  Sidekiq.hook_rails!
37
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
38
55
  end if defined?(::Rails)
39
56
  end
@@ -46,6 +46,7 @@ module Sidekiq
46
46
  @enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
47
47
  @sleeper = ConnectionPool::TimedStack.new
48
48
  @done = false
49
+ @thread = nil
49
50
  end
50
51
 
51
52
  # Shut down this instance, will pause until the thread is dead.
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sidekiq
3
- VERSION = "4.1.4"
3
+ VERSION = "4.2.0"
4
4
  end
@@ -1,26 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
  require 'erb'
3
- require 'yaml'
4
- require 'sinatra/base'
5
3
 
6
4
  require 'sidekiq'
7
5
  require 'sidekiq/api'
8
6
  require 'sidekiq/paginator'
9
- require 'sidekiq/web_helpers'
7
+ require 'sidekiq/web/helpers'
10
8
 
11
- module Sidekiq
12
- class Web < Sinatra::Base
13
- include Sidekiq::Paginator
9
+ require 'sidekiq/web/router'
10
+ require 'sidekiq/web/action'
11
+ require 'sidekiq/web/application'
14
12
 
15
- enable :sessions
16
- use ::Rack::Protection, :use => :authenticity_token unless ENV['RACK_ENV'] == 'test'
13
+ require 'rack/protection'
17
14
 
18
- set :root, File.expand_path(File.dirname(__FILE__) + "/../../web")
19
- set :public_folder, proc { "#{root}/assets" }
20
- set :views, proc { "#{root}/views" }
21
- set :locales, ["#{root}/locales"]
15
+ require 'rack/builder'
16
+ require 'rack/file'
17
+ require 'rack/session/cookie'
22
18
 
23
- helpers WebHelpers
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
24
26
 
25
27
  DEFAULT_TABS = {
26
28
  "Dashboard" => '',
@@ -32,6 +34,18 @@ module Sidekiq
32
34
  }
33
35
 
34
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
+
35
49
  def default_tabs
36
50
  DEFAULT_TABS
37
51
  end
@@ -41,234 +55,97 @@ module Sidekiq
41
55
  end
42
56
  alias_method :tabs, :custom_tabs
43
57
 
44
- attr_accessor :app_url
45
- end
46
-
47
- get "/busy" do
48
- erb :busy
49
- end
50
-
51
- post "/busy" do
52
- if params['identity']
53
- p = Sidekiq::Process.new('identity' => params['identity'])
54
- p.quiet! if params[:quiet]
55
- p.stop! if params[:stop]
56
- else
57
- processes.each do |pro|
58
- pro.quiet! if params[:quiet]
59
- pro.stop! if params[:stop]
60
- end
58
+ def locales
59
+ @locales ||= LOCALES
61
60
  end
62
- redirect "#{root_path}busy"
63
- end
64
61
 
65
- get "/queues" do
66
- @queues = Sidekiq::Queue.all
67
- erb :queues
68
- end
69
-
70
- get "/queues/:name" do
71
- halt 404 unless params[:name]
72
- @count = (params[:count] || 25).to_i
73
- @name = params[:name]
74
- @queue = Sidekiq::Queue.new(@name)
75
- (@current_page, @total_size, @messages) = page("queue:#{@name}", params[:page], @count)
76
- @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
77
- erb :queue
78
- end
79
-
80
- post "/queues/:name" do
81
- Sidekiq::Queue.new(params[:name]).clear
82
- redirect "#{root_path}queues"
83
- end
84
-
85
- post "/queues/:name/delete" do
86
- Sidekiq::Job.new(params[:key_val], params[:name]).delete
87
- redirect_with_query("#{root_path}queues/#{params[:name]}")
88
- end
89
-
90
- get '/morgue' do
91
- @count = (params[:count] || 25).to_i
92
- (@current_page, @total_size, @dead) = page("dead", params[:page], @count, reverse: true)
93
- @dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
94
- erb :morgue
95
- end
96
-
97
- get "/morgue/:key" do
98
- halt 404 unless params['key']
99
- @dead = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
100
- redirect "#{root_path}morgue" if @dead.nil?
101
- erb :dead
102
- end
103
-
104
- post '/morgue' do
105
- redirect request.path unless params['key']
106
-
107
- params['key'].each do |key|
108
- job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
109
- retry_or_delete_or_kill job, params if job
62
+ def views
63
+ @views ||= VIEWS
110
64
  end
111
- redirect_with_query("#{root_path}morgue")
112
- end
113
65
 
114
- post "/morgue/all/delete" do
115
- Sidekiq::DeadSet.new.clear
116
- redirect "#{root_path}morgue"
66
+ attr_accessor :app_url, :session_secret, :redis_pool
67
+ attr_writer :locales, :views
117
68
  end
118
69
 
119
- post "/morgue/all/retry" do
120
- Sidekiq::DeadSet.new.retry_all
121
- redirect "#{root_path}morgue"
70
+ def settings
71
+ self.class.settings
122
72
  end
123
73
 
124
- post "/morgue/:key" do
125
- halt 404 unless params['key']
126
- job = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
127
- retry_or_delete_or_kill job, params if job
128
- redirect_with_query("#{root_path}morgue")
74
+ def use(*middleware_args, &block)
75
+ middlewares << [middleware_args, block]
129
76
  end
130
77
 
131
-
132
- get '/retries' do
133
- @count = (params[:count] || 25).to_i
134
- (@current_page, @total_size, @retries) = page("retry", params[:page], @count)
135
- @retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
136
- erb :retries
137
- end
138
-
139
- get "/retries/:key" do
140
- @retry = Sidekiq::RetrySet.new.fetch(*parse_params(params['key'])).first
141
- redirect "#{root_path}retries" if @retry.nil?
142
- erb :retry
143
- end
144
-
145
- post '/retries' do
146
- redirect request.path unless params['key']
147
-
148
- params['key'].each do |key|
149
- job = Sidekiq::RetrySet.new.fetch(*parse_params(key)).first
150
- retry_or_delete_or_kill job, params if job
151
- end
152
- redirect_with_query("#{root_path}retries")
78
+ def middlewares
79
+ @middlewares ||= Web.middlewares.dup
153
80
  end
154
81
 
155
- post "/retries/all/delete" do
156
- Sidekiq::RetrySet.new.clear
157
- redirect "#{root_path}retries"
82
+ def call(env)
83
+ app.call(env)
158
84
  end
159
85
 
160
- post "/retries/all/retry" do
161
- Sidekiq::RetrySet.new.retry_all
162
- redirect "#{root_path}retries"
86
+ def self.call(env)
87
+ @app ||= new
88
+ @app.call(env)
163
89
  end
164
90
 
165
- post "/retries/:key" do
166
- job = Sidekiq::RetrySet.new.fetch(*parse_params(params['key'])).first
167
- retry_or_delete_or_kill job, params if job
168
- redirect_with_query("#{root_path}retries")
91
+ def app
92
+ @app ||= build
169
93
  end
170
94
 
171
- get '/scheduled' do
172
- @count = (params[:count] || 25).to_i
173
- (@current_page, @total_size, @scheduled) = page("schedule", params[:page], @count)
174
- @scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
175
- erb :scheduled
95
+ def self.register(extension)
96
+ extension.registered(WebApplication)
176
97
  end
177
98
 
178
- get "/scheduled/:key" do
179
- @job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
180
- redirect "#{root_path}scheduled" if @job.nil?
181
- erb :scheduled_job_info
182
- end
183
-
184
- post '/scheduled' do
185
- redirect request.path unless params['key']
99
+ private
186
100
 
187
- params['key'].each do |key|
188
- job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
189
- delete_or_add_queue job, params if job
101
+ def using?(middleware)
102
+ middlewares.any? do |(m,_)|
103
+ m.kind_of?(Array) && (m[0] == middleware || m[0].kind_of?(middleware))
190
104
  end
191
- redirect_with_query("#{root_path}scheduled")
192
- end
193
-
194
- post "/scheduled/:key" do
195
- halt 404 unless params['key']
196
- job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
197
- delete_or_add_queue job, params if job
198
- redirect_with_query("#{root_path}scheduled")
199
- end
200
-
201
- get '/' do
202
- @redis_info = redis_info.select{ |k, v| REDIS_KEYS.include? k }
203
- stats_history = Sidekiq::Stats::History.new((params[:days] || 30).to_i)
204
- @processed_history = stats_history.processed
205
- @failed_history = stats_history.failed
206
- erb :dashboard
207
105
  end
208
106
 
209
- REDIS_KEYS = %w(redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human)
107
+ def build
108
+ middlewares = self.middlewares
109
+ klass = self.class
210
110
 
211
- get '/dashboard/stats' do
212
- redirect "#{root_path}stats"
213
- end
214
-
215
- get '/stats' do
216
- sidekiq_stats = Sidekiq::Stats.new
217
- redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
218
-
219
- content_type :json
220
- Sidekiq.dump_json(
221
- sidekiq: {
222
- processed: sidekiq_stats.processed,
223
- failed: sidekiq_stats.failed,
224
- busy: sidekiq_stats.workers_size,
225
- processes: sidekiq_stats.processes_size,
226
- enqueued: sidekiq_stats.enqueued,
227
- scheduled: sidekiq_stats.scheduled_size,
228
- retries: sidekiq_stats.retry_size,
229
- dead: sidekiq_stats.dead_size,
230
- default_latency: sidekiq_stats.default_queue_latency
231
- },
232
- redis: redis_stats
233
- )
234
- end
111
+ unless using?(::Rack::Protection) || ENV['RACK_ENV'] == 'test'
112
+ middlewares.unshift [[::Rack::Protection, { use: :authenticity_token }], nil]
113
+ end
235
114
 
236
- get '/stats/queues' do
237
- queue_stats = Sidekiq::Stats::Queues.new
115
+ unless using? ::Rack::Session::Cookie
116
+ unless secret = Web.session_secret
117
+ require 'securerandom'
118
+ secret = SecureRandom.hex(64)
119
+ end
238
120
 
239
- content_type :json
240
- Sidekiq.dump_json(
241
- queue_stats.lengths
242
- )
243
- end
121
+ middlewares.unshift [[::Rack::Session::Cookie, { secret: secret }], nil]
122
+ end
244
123
 
245
- private
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
246
130
 
247
- def retry_or_delete_or_kill job, params
248
- if params['retry']
249
- job.retry
250
- elsif params['delete']
251
- job.delete
252
- elsif params['kill']
253
- job.kill
254
- end
255
- end
131
+ middlewares.each {|middleware, block| use(*middleware, &block) }
256
132
 
257
- def delete_or_add_queue job, params
258
- if params['delete']
259
- job.delete
260
- elsif params['add_to_queue']
261
- job.add_to_queue
133
+ run WebApplication.new(klass)
262
134
  end
263
135
  end
264
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"
265
142
  end
266
143
 
267
144
  if defined?(::ActionDispatch::Request::Session) &&
268
145
  !::ActionDispatch::Request::Session.respond_to?(:each)
269
146
  # mperham/sidekiq#2460
270
147
  # Rack apps can't reuse the Rails session store without
271
- # this monkeypatch
148
+ # this monkeypatch, fixed in Rails 5.
272
149
  class ActionDispatch::Request::Session
273
150
  def each(&block)
274
151
  hash = self.to_hash