sidekiq 3.4.1 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +1118 -4
  3. data/LICENSE.txt +9 -0
  4. data/README.md +55 -47
  5. data/bin/multi_queue_bench +271 -0
  6. data/bin/sidekiq +26 -3
  7. data/bin/sidekiqload +247 -0
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/generators/sidekiq/job_generator.rb +57 -0
  10. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  11. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  12. data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
  13. data/lib/sidekiq/api.rb +714 -312
  14. data/lib/sidekiq/capsule.rb +130 -0
  15. data/lib/sidekiq/cli.rb +275 -241
  16. data/lib/sidekiq/client.rb +141 -110
  17. data/lib/sidekiq/component.rb +68 -0
  18. data/lib/sidekiq/config.rb +291 -0
  19. data/lib/sidekiq/deploy.rb +62 -0
  20. data/lib/sidekiq/embedded.rb +61 -0
  21. data/lib/sidekiq/fetch.rb +53 -121
  22. data/lib/sidekiq/iterable_job.rb +53 -0
  23. data/lib/sidekiq/job/interrupt_handler.rb +22 -0
  24. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  25. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  26. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  27. data/lib/sidekiq/job/iterable.rb +231 -0
  28. data/lib/sidekiq/job.rb +385 -0
  29. data/lib/sidekiq/job_logger.rb +64 -0
  30. data/lib/sidekiq/job_retry.rb +305 -0
  31. data/lib/sidekiq/job_util.rb +107 -0
  32. data/lib/sidekiq/launcher.rb +241 -66
  33. data/lib/sidekiq/logger.rb +131 -0
  34. data/lib/sidekiq/manager.rb +91 -192
  35. data/lib/sidekiq/metrics/query.rb +156 -0
  36. data/lib/sidekiq/metrics/shared.rb +95 -0
  37. data/lib/sidekiq/metrics/tracking.rb +140 -0
  38. data/lib/sidekiq/middleware/chain.rb +114 -56
  39. data/lib/sidekiq/middleware/current_attributes.rb +111 -0
  40. data/lib/sidekiq/middleware/i18n.rb +8 -7
  41. data/lib/sidekiq/middleware/modules.rb +21 -0
  42. data/lib/sidekiq/monitor.rb +146 -0
  43. data/lib/sidekiq/paginator.rb +29 -16
  44. data/lib/sidekiq/processor.rb +248 -112
  45. data/lib/sidekiq/rails.rb +61 -27
  46. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  47. data/lib/sidekiq/redis_connection.rb +68 -48
  48. data/lib/sidekiq/ring_buffer.rb +29 -0
  49. data/lib/sidekiq/scheduled.rb +173 -52
  50. data/lib/sidekiq/sd_notify.rb +149 -0
  51. data/lib/sidekiq/systemd.rb +24 -0
  52. data/lib/sidekiq/testing/inline.rb +7 -5
  53. data/lib/sidekiq/testing.rb +206 -65
  54. data/lib/sidekiq/transaction_aware_client.rb +51 -0
  55. data/lib/sidekiq/version.rb +4 -1
  56. data/lib/sidekiq/web/action.rb +99 -0
  57. data/lib/sidekiq/web/application.rb +479 -0
  58. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  59. data/lib/sidekiq/web/helpers.rb +415 -0
  60. data/lib/sidekiq/web/router.rb +104 -0
  61. data/lib/sidekiq/web.rb +158 -200
  62. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  63. data/lib/sidekiq.rb +100 -132
  64. data/sidekiq.gemspec +27 -23
  65. data/web/assets/images/apple-touch-icon.png +0 -0
  66. data/web/assets/images/favicon.ico +0 -0
  67. data/web/assets/javascripts/application.js +177 -72
  68. data/web/assets/javascripts/base-charts.js +106 -0
  69. data/web/assets/javascripts/chart.min.js +13 -0
  70. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  71. data/web/assets/javascripts/dashboard-charts.js +192 -0
  72. data/web/assets/javascripts/dashboard.js +37 -286
  73. data/web/assets/javascripts/metrics.js +298 -0
  74. data/web/assets/stylesheets/application-dark.css +147 -0
  75. data/web/assets/stylesheets/application-rtl.css +163 -0
  76. data/web/assets/stylesheets/application.css +228 -247
  77. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  78. data/web/assets/stylesheets/bootstrap.css +4 -8
  79. data/web/locales/ar.yml +87 -0
  80. data/web/locales/cs.yml +62 -52
  81. data/web/locales/da.yml +60 -53
  82. data/web/locales/de.yml +65 -53
  83. data/web/locales/el.yml +43 -24
  84. data/web/locales/en.yml +86 -61
  85. data/web/locales/es.yml +70 -53
  86. data/web/locales/fa.yml +80 -0
  87. data/web/locales/fr.yml +86 -56
  88. data/web/locales/gd.yml +99 -0
  89. data/web/locales/he.yml +80 -0
  90. data/web/locales/hi.yml +59 -59
  91. data/web/locales/it.yml +53 -53
  92. data/web/locales/ja.yml +78 -56
  93. data/web/locales/ko.yml +52 -52
  94. data/web/locales/lt.yml +83 -0
  95. data/web/locales/{no.yml → nb.yml} +62 -54
  96. data/web/locales/nl.yml +52 -52
  97. data/web/locales/pl.yml +45 -45
  98. data/web/locales/pt-br.yml +83 -55
  99. data/web/locales/pt.yml +51 -51
  100. data/web/locales/ru.yml +68 -60
  101. data/web/locales/sv.yml +53 -53
  102. data/web/locales/ta.yml +60 -60
  103. data/web/locales/tr.yml +101 -0
  104. data/web/locales/uk.yml +77 -0
  105. data/web/locales/ur.yml +80 -0
  106. data/web/locales/vi.yml +83 -0
  107. data/web/locales/zh-cn.yml +43 -16
  108. data/web/locales/zh-tw.yml +42 -8
  109. data/web/views/_footer.erb +22 -9
  110. data/web/views/_job_info.erb +27 -6
  111. data/web/views/_metrics_period_select.erb +12 -0
  112. data/web/views/_nav.erb +8 -22
  113. data/web/views/_paging.erb +3 -1
  114. data/web/views/_poll_link.erb +4 -0
  115. data/web/views/_summary.erb +7 -7
  116. data/web/views/busy.erb +91 -31
  117. data/web/views/dashboard.erb +52 -22
  118. data/web/views/dead.erb +5 -4
  119. data/web/views/filtering.erb +7 -0
  120. data/web/views/layout.erb +19 -7
  121. data/web/views/metrics.erb +91 -0
  122. data/web/views/metrics_for_job.erb +59 -0
  123. data/web/views/morgue.erb +26 -20
  124. data/web/views/queue.erb +36 -25
  125. data/web/views/queues.erb +24 -7
  126. data/web/views/retries.erb +29 -21
  127. data/web/views/retry.erb +6 -5
  128. data/web/views/scheduled.erb +20 -17
  129. data/web/views/scheduled_job_info.erb +2 -1
  130. metadata +101 -232
  131. data/.gitignore +0 -12
  132. data/.travis.yml +0 -16
  133. data/3.0-Upgrade.md +0 -70
  134. data/COMM-LICENSE +0 -85
  135. data/Contributing.md +0 -32
  136. data/Gemfile +0 -22
  137. data/LICENSE +0 -9
  138. data/Pro-2.0-Upgrade.md +0 -138
  139. data/Pro-Changes.md +0 -412
  140. data/Rakefile +0 -9
  141. data/bin/sidekiqctl +0 -93
  142. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  143. data/lib/generators/sidekiq/templates/worker_test.rb.erb +0 -8
  144. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  145. data/lib/sidekiq/actor.rb +0 -39
  146. data/lib/sidekiq/core_ext.rb +0 -105
  147. data/lib/sidekiq/exception_handler.rb +0 -30
  148. data/lib/sidekiq/extensions/action_mailer.rb +0 -56
  149. data/lib/sidekiq/extensions/active_record.rb +0 -39
  150. data/lib/sidekiq/extensions/class_methods.rb +0 -39
  151. data/lib/sidekiq/extensions/generic_proxy.rb +0 -24
  152. data/lib/sidekiq/logging.rb +0 -104
  153. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  154. data/lib/sidekiq/middleware/server/logging.rb +0 -35
  155. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -206
  156. data/lib/sidekiq/util.rb +0 -55
  157. data/lib/sidekiq/web_helpers.rb +0 -234
  158. data/lib/sidekiq/worker.rb +0 -89
  159. data/test/config.yml +0 -9
  160. data/test/env_based_config.yml +0 -11
  161. data/test/fake_env.rb +0 -0
  162. data/test/fixtures/en.yml +0 -2
  163. data/test/helper.rb +0 -39
  164. data/test/test_api.rb +0 -494
  165. data/test/test_cli.rb +0 -365
  166. data/test/test_client.rb +0 -269
  167. data/test/test_exception_handler.rb +0 -55
  168. data/test/test_extensions.rb +0 -120
  169. data/test/test_fetch.rb +0 -104
  170. data/test/test_logging.rb +0 -34
  171. data/test/test_manager.rb +0 -164
  172. data/test/test_middleware.rb +0 -159
  173. data/test/test_processor.rb +0 -166
  174. data/test/test_redis_connection.rb +0 -127
  175. data/test/test_retry.rb +0 -373
  176. data/test/test_scheduled.rb +0 -120
  177. data/test/test_scheduling.rb +0 -71
  178. data/test/test_sidekiq.rb +0 -69
  179. data/test/test_testing.rb +0 -82
  180. data/test/test_testing_fake.rb +0 -271
  181. data/test/test_testing_inline.rb +0 -93
  182. data/test/test_web.rb +0 -594
  183. data/test/test_web_helpers.rb +0 -52
  184. data/test/test_worker_generator.rb +0 -17
  185. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  186. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  187. data/web/assets/images/status/active.png +0 -0
  188. data/web/assets/images/status/idle.png +0 -0
  189. data/web/assets/javascripts/locales/README.md +0 -27
  190. data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
  191. data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
  192. data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
  193. data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
  194. data/web/assets/javascripts/locales/jquery.timeago.cs.js +0 -18
  195. data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
  196. data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
  197. data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
  198. data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
  199. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
  200. data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
  201. data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
  202. data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
  203. data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
  204. data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
  205. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
  206. data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
  207. data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
  208. data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
  209. data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
  210. data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
  211. data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
  212. data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
  213. data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
  214. data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
  215. data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
  216. data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
  217. data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
  218. data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
  219. data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
  220. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
  221. data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
  222. data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
  223. data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
  224. data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
  225. data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
  226. data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
  227. data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
  228. data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
  229. data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
  230. data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
  231. data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
  232. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +0 -20
  233. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +0 -20
  234. data/web/views/_poll.erb +0 -10
  235. /data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
data/lib/sidekiq/web.rb CHANGED
@@ -1,33 +1,57 @@
1
- require 'erb'
2
- require 'yaml'
3
- require 'sinatra/base'
1
+ # frozen_string_literal: true
4
2
 
5
- require 'sidekiq'
6
- require 'sidekiq/api'
7
- require 'sidekiq/paginator'
8
- require 'sidekiq/web_helpers'
3
+ require "erb"
4
+ require "securerandom"
9
5
 
10
- module Sidekiq
11
- class Web < Sinatra::Base
12
- include Sidekiq::Paginator
6
+ require "sidekiq"
7
+ require "sidekiq/api"
8
+ require "sidekiq/paginator"
9
+ require "sidekiq/web/helpers"
10
+
11
+ require "sidekiq/web/router"
12
+ require "sidekiq/web/action"
13
+ require "sidekiq/web/application"
14
+ require "sidekiq/web/csrf_protection"
13
15
 
14
- set :root, File.expand_path(File.dirname(__FILE__) + "/../../web")
15
- set :public_folder, proc { "#{root}/assets" }
16
- set :views, proc { "#{root}/views" }
17
- set :locales, ["#{root}/locales"]
16
+ require "rack/content_length"
17
+ require "rack/builder"
18
+ require "rack/static"
18
19
 
19
- helpers WebHelpers
20
+ module Sidekiq
21
+ class Web
22
+ ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../web")
23
+ VIEWS = "#{ROOT}/views"
24
+ LOCALES = ["#{ROOT}/locales"]
25
+ LAYOUT = "#{VIEWS}/layout.erb"
26
+ ASSETS = "#{ROOT}/assets"
20
27
 
21
28
  DEFAULT_TABS = {
22
- "Dashboard" => '',
23
- "Busy" => 'busy',
24
- "Queues" => 'queues',
25
- "Retries" => 'retries',
26
- "Scheduled" => 'scheduled',
27
- "Dead" => 'morgue',
29
+ "Dashboard" => "",
30
+ "Busy" => "busy",
31
+ "Queues" => "queues",
32
+ "Retries" => "retries",
33
+ "Scheduled" => "scheduled",
34
+ "Dead" => "morgue",
35
+ "Metrics" => "metrics"
28
36
  }
29
37
 
38
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
39
+ CONTENT_LANGUAGE = "Content-Language"
40
+ CONTENT_SECURITY_POLICY = "Content-Security-Policy"
41
+ LOCATION = "Location"
42
+ X_CASCADE = "X-Cascade"
43
+ else
44
+ CONTENT_LANGUAGE = "content-language"
45
+ CONTENT_SECURITY_POLICY = "content-security-policy"
46
+ LOCATION = "location"
47
+ X_CASCADE = "x-cascade"
48
+ end
49
+
30
50
  class << self
51
+ def settings
52
+ self
53
+ end
54
+
31
55
  def default_tabs
32
56
  DEFAULT_TABS
33
57
  end
@@ -37,225 +61,159 @@ module Sidekiq
37
61
  end
38
62
  alias_method :tabs, :custom_tabs
39
63
 
40
- attr_accessor :app_url
41
- end
42
-
43
- get "/busy" do
44
- erb :busy
45
- end
46
-
47
- post "/busy" do
48
- if params['identity']
49
- p = Sidekiq::Process.new('identity' => params['identity'])
50
- p.quiet! if params[:quiet]
51
- p.stop! if params[:stop]
52
- else
53
- processes.each do |pro|
54
- pro.quiet! if params[:quiet]
55
- pro.stop! if params[:stop]
56
- end
64
+ def custom_job_info_rows
65
+ @custom_job_info_rows ||= []
57
66
  end
58
- redirect "#{root_path}busy"
59
- end
60
-
61
- get "/queues" do
62
- @queues = Sidekiq::Queue.all
63
- erb :queues
64
- end
65
67
 
66
- get "/queues/:name" do
67
- halt 404 unless params[:name]
68
- @count = (params[:count] || 25).to_i
69
- @name = params[:name]
70
- @queue = Sidekiq::Queue.new(@name)
71
- (@current_page, @total_size, @messages) = page("queue:#{@name}", params[:page], @count)
72
- @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
73
- erb :queue
74
- end
68
+ def locales
69
+ @locales ||= LOCALES
70
+ end
75
71
 
76
- post "/queues/:name" do
77
- Sidekiq::Queue.new(params[:name]).clear
78
- redirect "#{root_path}queues"
79
- end
72
+ def views
73
+ @views ||= VIEWS
74
+ end
80
75
 
81
- post "/queues/:name/delete" do
82
- Sidekiq::Job.new(params[:key_val], params[:name]).delete
83
- redirect_with_query("#{root_path}queues/#{params[:name]}")
84
- end
76
+ def enable(*opts)
77
+ opts.each { |key| set(key, true) }
78
+ end
85
79
 
86
- get '/morgue' do
87
- @count = (params[:count] || 25).to_i
88
- (@current_page, @total_size, @dead) = page("dead", params[:page], @count, reverse: true)
89
- @dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
90
- erb :morgue
91
- end
80
+ def disable(*opts)
81
+ opts.each { |key| set(key, false) }
82
+ end
92
83
 
93
- get "/morgue/:key" do
94
- halt 404 unless params['key']
95
- @dead = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
96
- redirect "#{root_path}morgue" if @dead.nil?
97
- erb :dead
98
- end
84
+ def middlewares
85
+ @middlewares ||= []
86
+ end
99
87
 
100
- post '/morgue' do
101
- halt 404 unless params['key']
88
+ def use(*args, &block)
89
+ middlewares << [args, block]
90
+ end
102
91
 
103
- params['key'].each do |key|
104
- job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
105
- retry_or_delete_or_kill job, params if job
92
+ def set(attribute, value)
93
+ send(:"#{attribute}=", value)
106
94
  end
107
- redirect_with_query("#{root_path}morgue")
108
- end
109
95
 
110
- post "/morgue/all/delete" do
111
- Sidekiq::DeadSet.new.clear
112
- redirect "#{root_path}morgue"
96
+ attr_accessor :app_url, :redis_pool
97
+ attr_writer :locales, :views
113
98
  end
114
99
 
115
- post "/morgue/all/retry" do
116
- Sidekiq::DeadSet.new.retry_all
117
- redirect "#{root_path}morgue"
100
+ def self.inherited(child)
101
+ child.app_url = app_url
102
+ child.redis_pool = redis_pool
118
103
  end
119
104
 
120
- post "/morgue/:key" do
121
- halt 404 unless params['key']
122
- job = Sidekiq::DeadSet.new.fetch(*parse_params(params['key'])).first
123
- retry_or_delete_or_kill job, params if job
124
- redirect_with_query("#{root_path}morgue")
105
+ def settings
106
+ self.class.settings
125
107
  end
126
108
 
127
-
128
- get '/retries' do
129
- @count = (params[:count] || 25).to_i
130
- (@current_page, @total_size, @retries) = page("retry", params[:page], @count)
131
- @retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
132
- erb :retries
109
+ def middlewares
110
+ @middlewares ||= self.class.middlewares
133
111
  end
134
112
 
135
- get "/retries/:key" do
136
- @retry = Sidekiq::RetrySet.new.fetch(*parse_params(params['key'])).first
137
- redirect "#{root_path}retries" if @retry.nil?
138
- erb :retry
113
+ def use(*args, &block)
114
+ middlewares << [args, block]
139
115
  end
140
116
 
141
- post '/retries' do
142
- redirect request.path unless params['key']
143
-
144
- params['key'].each do |key|
145
- job = Sidekiq::RetrySet.new.fetch(*parse_params(key)).first
146
- retry_or_delete_or_kill job, params if job
147
- end
148
- redirect_with_query("#{root_path}retries")
117
+ def call(env)
118
+ env[:csp_nonce] = SecureRandom.base64(16)
119
+ app.call(env)
149
120
  end
150
121
 
151
- post "/retries/all/delete" do
152
- Sidekiq::RetrySet.new.clear
153
- redirect "#{root_path}retries"
122
+ def self.call(env)
123
+ @app ||= new
124
+ @app.call(env)
154
125
  end
155
126
 
156
- post "/retries/all/retry" do
157
- Sidekiq::RetrySet.new.retry_all
158
- redirect "#{root_path}retries"
127
+ def app
128
+ @app ||= build
159
129
  end
160
130
 
161
- post "/retries/:key" do
162
- job = Sidekiq::RetrySet.new.fetch(*parse_params(params['key'])).first
163
- retry_or_delete_or_kill job, params if job
164
- redirect_with_query("#{root_path}retries")
131
+ def enable(*opts)
132
+ opts.each { |key| set(key, true) }
165
133
  end
166
134
 
167
- get '/scheduled' do
168
- @count = (params[:count] || 25).to_i
169
- (@current_page, @total_size, @scheduled) = page("schedule", params[:page], @count)
170
- @scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
171
- erb :scheduled
135
+ def disable(*opts)
136
+ opts.each { |key| set(key, false) }
172
137
  end
173
138
 
174
- get "/scheduled/:key" do
175
- @job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
176
- redirect "#{root_path}scheduled" if @job.nil?
177
- erb :scheduled_job_info
139
+ def set(attribute, value)
140
+ send(:"#{attribute}=", value)
178
141
  end
179
142
 
180
- post '/scheduled' do
181
- redirect request.path unless params['key']
182
-
183
- params['key'].each do |key|
184
- job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
185
- delete_or_add_queue job, params if job
143
+ # Register a class as a Sidekiq Web UI extension. The class should
144
+ # provide one or more tabs which map to an index route. Options:
145
+ #
146
+ # @param extension [Class] Class which contains the HTTP actions, required
147
+ # @param name [String] the name of the extension, used to namespace assets
148
+ # @param tab [String | Array] labels(s) of the UI tabs
149
+ # @param index [String | Array] index route(s) for each tab
150
+ # @param root_dir [String] directory location to find assets, locales and views, typically `web/` within the gemfile
151
+ # @param asset_paths [Array] one or more directories under {root}/assets/{name} to be publicly served, e.g. ["js", "css", "img"]
152
+ # @param cache_for [Integer] amount of time to cache assets, default one day
153
+ #
154
+ # TODO name, tab and index will be mandatory in 8.0
155
+ #
156
+ # Web extensions will have a root `web/` directory with `locales/`, `assets/`
157
+ # and `views/` subdirectories.
158
+ def self.register(extension, name: nil, tab: nil, index: nil, root_dir: nil, cache_for: 86400, asset_paths: nil)
159
+ tab = Array(tab)
160
+ index = Array(index)
161
+ tab.zip(index).each do |tab, index|
162
+ tabs[tab] = index
163
+ end
164
+ if root_dir
165
+ locdir = File.join(root_dir, "locales")
166
+ locales << locdir if File.directory?(locdir)
167
+
168
+ if asset_paths && name
169
+ # if you have {root}/assets/{name}/js/scripts.js
170
+ # and {root}/assets/{name}/css/styles.css
171
+ # you would pass in:
172
+ # asset_paths: ["js", "css"]
173
+ # See script_tag and style_tag in web/helpers.rb
174
+ assdir = File.join(root_dir, "assets")
175
+ assurls = Array(asset_paths).map { |x| "/#{name}/#{x}" }
176
+ assetprops = {
177
+ urls: assurls,
178
+ root: assdir,
179
+ cascade: true
180
+ }
181
+ assetprops[:header_rules] = [[:all, {Rack::CACHE_CONTROL => "private, max-age=#{cache_for.to_i}"}]] if cache_for
182
+ middlewares << [[Rack::Static, assetprops], nil]
183
+ end
186
184
  end
187
- redirect_with_query("#{root_path}scheduled")
188
- end
189
-
190
- post "/scheduled/:key" do
191
- halt 404 unless params['key']
192
- job = Sidekiq::ScheduledSet.new.fetch(*parse_params(params['key'])).first
193
- delete_or_add_queue job, params if job
194
- redirect_with_query("#{root_path}scheduled")
195
- end
196
-
197
- get '/' do
198
- @redis_info = redis_info.select{ |k, v| REDIS_KEYS.include? k }
199
- stats_history = Sidekiq::Stats::History.new((params[:days] || 30).to_i)
200
- @processed_history = stats_history.processed
201
- @failed_history = stats_history.failed
202
- erb :dashboard
203
- end
204
-
205
- REDIS_KEYS = %w(redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human)
206
-
207
- get '/dashboard/stats' do
208
- redirect "#{root_path}stats"
209
- end
210
-
211
- get '/stats' do
212
- sidekiq_stats = Sidekiq::Stats.new
213
- redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
214
-
215
- content_type :json
216
- Sidekiq.dump_json(
217
- sidekiq: {
218
- processed: sidekiq_stats.processed,
219
- failed: sidekiq_stats.failed,
220
- busy: sidekiq_stats.workers_size,
221
- processes: sidekiq_stats.processes_size,
222
- enqueued: sidekiq_stats.enqueued,
223
- scheduled: sidekiq_stats.scheduled_size,
224
- retries: sidekiq_stats.retry_size,
225
- dead: sidekiq_stats.dead_size,
226
- default_latency: sidekiq_stats.default_queue_latency
227
- },
228
- redis: redis_stats
229
- )
230
- end
231
-
232
- get '/stats/queues' do
233
- queue_stats = Sidekiq::Stats::Queues.new
234
185
 
235
- content_type :json
236
- Sidekiq.dump_json(
237
- queue_stats.lengths
238
- )
186
+ yield self if block_given?
187
+ extension.registered(WebApplication)
239
188
  end
240
189
 
241
190
  private
242
191
 
243
- def retry_or_delete_or_kill job, params
244
- if params['retry']
245
- job.retry
246
- elsif params['delete']
247
- job.delete
248
- elsif params['kill']
249
- job.kill
192
+ def build
193
+ klass = self.class
194
+ m = middlewares
195
+
196
+ rules = []
197
+ rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
198
+
199
+ ::Rack::Builder.new do
200
+ use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
201
+ root: ASSETS,
202
+ cascade: true,
203
+ header_rules: rules
204
+ m.each { |middleware, block| use(*middleware, &block) }
205
+ use Sidekiq::Web::CsrfProtection unless $TESTING
206
+ run WebApplication.new(klass)
250
207
  end
251
208
  end
209
+ end
252
210
 
253
- def delete_or_add_queue job, params
254
- if params['delete']
255
- job.delete
256
- elsif params['add_to_queue']
257
- job.add_to_queue
258
- end
211
+ Sidekiq::WebApplication.helpers WebHelpers
212
+ Sidekiq::WebApplication.helpers Sidekiq::Paginator
213
+
214
+ Sidekiq::WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
215
+ def _render
216
+ #{ERB.new(File.read(Web::LAYOUT)).src}
259
217
  end
260
- end
218
+ RUBY
261
219
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ # Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
5
+ # Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
6
+ #
7
+ # The term "worker" is too generic and overly confusing, used in several
8
+ # different contexts meaning different things. Many people call a Sidekiq
9
+ # process a "worker". Some people call the thread that executes jobs a
10
+ # "worker". This change brings Sidekiq closer to ActiveJob where your job
11
+ # classes extend ApplicationJob.
12
+ Worker = Job
13
+ end