sidekiq 7.1.4 → 8.0.9

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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +333 -0
  3. data/README.md +16 -13
  4. data/bin/multi_queue_bench +271 -0
  5. data/bin/sidekiqload +31 -22
  6. data/bin/webload +69 -0
  7. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +121 -0
  8. data/lib/generators/sidekiq/job_generator.rb +2 -0
  9. data/lib/generators/sidekiq/templates/job.rb.erb +1 -1
  10. data/lib/sidekiq/api.rb +260 -67
  11. data/lib/sidekiq/capsule.rb +17 -8
  12. data/lib/sidekiq/cli.rb +19 -20
  13. data/lib/sidekiq/client.rb +48 -15
  14. data/lib/sidekiq/component.rb +64 -3
  15. data/lib/sidekiq/config.rb +60 -18
  16. data/lib/sidekiq/deploy.rb +4 -2
  17. data/lib/sidekiq/embedded.rb +4 -1
  18. data/lib/sidekiq/fetch.rb +2 -1
  19. data/lib/sidekiq/iterable_job.rb +56 -0
  20. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  21. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  22. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  23. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  24. data/lib/sidekiq/job/iterable.rb +322 -0
  25. data/lib/sidekiq/job.rb +16 -5
  26. data/lib/sidekiq/job_logger.rb +15 -12
  27. data/lib/sidekiq/job_retry.rb +41 -13
  28. data/lib/sidekiq/job_util.rb +7 -1
  29. data/lib/sidekiq/launcher.rb +23 -11
  30. data/lib/sidekiq/loader.rb +57 -0
  31. data/lib/sidekiq/logger.rb +25 -69
  32. data/lib/sidekiq/manager.rb +0 -1
  33. data/lib/sidekiq/metrics/query.rb +76 -45
  34. data/lib/sidekiq/metrics/shared.rb +23 -9
  35. data/lib/sidekiq/metrics/tracking.rb +32 -15
  36. data/lib/sidekiq/middleware/current_attributes.rb +39 -14
  37. data/lib/sidekiq/middleware/i18n.rb +2 -0
  38. data/lib/sidekiq/middleware/modules.rb +2 -0
  39. data/lib/sidekiq/monitor.rb +6 -9
  40. data/lib/sidekiq/paginator.rb +16 -3
  41. data/lib/sidekiq/processor.rb +37 -20
  42. data/lib/sidekiq/profiler.rb +73 -0
  43. data/lib/sidekiq/rails.rb +47 -57
  44. data/lib/sidekiq/redis_client_adapter.rb +25 -8
  45. data/lib/sidekiq/redis_connection.rb +49 -9
  46. data/lib/sidekiq/ring_buffer.rb +3 -0
  47. data/lib/sidekiq/scheduled.rb +2 -2
  48. data/lib/sidekiq/systemd.rb +2 -0
  49. data/lib/sidekiq/testing.rb +34 -15
  50. data/lib/sidekiq/transaction_aware_client.rb +20 -5
  51. data/lib/sidekiq/version.rb +6 -2
  52. data/lib/sidekiq/web/action.rb +149 -64
  53. data/lib/sidekiq/web/application.rb +367 -297
  54. data/lib/sidekiq/web/config.rb +120 -0
  55. data/lib/sidekiq/web/csrf_protection.rb +8 -5
  56. data/lib/sidekiq/web/helpers.rb +146 -64
  57. data/lib/sidekiq/web/router.rb +61 -74
  58. data/lib/sidekiq/web.rb +53 -106
  59. data/lib/sidekiq.rb +11 -4
  60. data/sidekiq.gemspec +6 -5
  61. data/web/assets/images/logo.png +0 -0
  62. data/web/assets/images/status.png +0 -0
  63. data/web/assets/javascripts/application.js +66 -24
  64. data/web/assets/javascripts/base-charts.js +30 -16
  65. data/web/assets/javascripts/chartjs-adapter-date-fns.min.js +7 -0
  66. data/web/assets/javascripts/dashboard-charts.js +37 -11
  67. data/web/assets/javascripts/dashboard.js +15 -11
  68. data/web/assets/javascripts/metrics.js +50 -34
  69. data/web/assets/stylesheets/style.css +776 -0
  70. data/web/locales/ar.yml +2 -0
  71. data/web/locales/cs.yml +2 -0
  72. data/web/locales/da.yml +2 -0
  73. data/web/locales/de.yml +2 -0
  74. data/web/locales/el.yml +2 -0
  75. data/web/locales/en.yml +12 -1
  76. data/web/locales/es.yml +25 -2
  77. data/web/locales/fa.yml +2 -0
  78. data/web/locales/fr.yml +2 -1
  79. data/web/locales/gd.yml +2 -1
  80. data/web/locales/he.yml +2 -0
  81. data/web/locales/hi.yml +2 -0
  82. data/web/locales/it.yml +41 -1
  83. data/web/locales/ja.yml +2 -1
  84. data/web/locales/ko.yml +2 -0
  85. data/web/locales/lt.yml +2 -0
  86. data/web/locales/nb.yml +2 -0
  87. data/web/locales/nl.yml +2 -0
  88. data/web/locales/pl.yml +2 -0
  89. data/web/locales/{pt-br.yml → pt-BR.yml} +4 -3
  90. data/web/locales/pt.yml +2 -0
  91. data/web/locales/ru.yml +2 -0
  92. data/web/locales/sv.yml +2 -0
  93. data/web/locales/ta.yml +2 -0
  94. data/web/locales/tr.yml +102 -0
  95. data/web/locales/uk.yml +29 -4
  96. data/web/locales/ur.yml +2 -0
  97. data/web/locales/vi.yml +2 -0
  98. data/web/locales/{zh-cn.yml → zh-CN.yml} +86 -74
  99. data/web/locales/{zh-tw.yml → zh-TW.yml} +3 -2
  100. data/web/views/_footer.erb +31 -22
  101. data/web/views/_job_info.erb +91 -89
  102. data/web/views/_metrics_period_select.erb +13 -10
  103. data/web/views/_nav.erb +14 -21
  104. data/web/views/_paging.erb +22 -21
  105. data/web/views/_poll_link.erb +2 -2
  106. data/web/views/_summary.erb +23 -23
  107. data/web/views/busy.erb +123 -125
  108. data/web/views/dashboard.erb +71 -82
  109. data/web/views/dead.erb +31 -27
  110. data/web/views/filtering.erb +6 -0
  111. data/web/views/layout.erb +13 -29
  112. data/web/views/metrics.erb +70 -68
  113. data/web/views/metrics_for_job.erb +30 -40
  114. data/web/views/morgue.erb +65 -70
  115. data/web/views/profiles.erb +43 -0
  116. data/web/views/queue.erb +54 -52
  117. data/web/views/queues.erb +43 -37
  118. data/web/views/retries.erb +70 -75
  119. data/web/views/retry.erb +32 -27
  120. data/web/views/scheduled.erb +63 -55
  121. data/web/views/scheduled_job_info.erb +3 -3
  122. metadata +49 -27
  123. data/web/assets/stylesheets/application-dark.css +0 -147
  124. data/web/assets/stylesheets/application-rtl.css +0 -153
  125. data/web/assets/stylesheets/application.css +0 -724
  126. data/web/assets/stylesheets/bootstrap-rtl.min.css +0 -9
  127. data/web/assets/stylesheets/bootstrap.css +0 -5
  128. data/web/views/_status.erb +0 -4
@@ -1,93 +1,178 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "erb"
4
+
3
5
  module Sidekiq
4
- class WebAction
5
- RACK_SESSION = "rack.session"
6
+ class Web
7
+ ##
8
+ # These instance methods are available to all executing ERB
9
+ # templates.
10
+ class Action
11
+ attr_accessor :env, :block
12
+
13
+ def initialize(env, block)
14
+ @_erb = false
15
+ @env = env
16
+ @block = block
17
+ end
6
18
 
7
- attr_accessor :env, :block, :type
19
+ def config
20
+ env[:web_config]
21
+ end
8
22
 
9
- def settings
10
- Web.settings
11
- end
23
+ def request
24
+ @request ||= ::Rack::Request.new(env)
25
+ end
12
26
 
13
- def request
14
- @request ||= ::Rack::Request.new(env)
15
- end
27
+ def halt(res)
28
+ throw :halt, [res, {"content-type" => "text/plain"}, [res.to_s]]
29
+ end
16
30
 
17
- def halt(res)
18
- throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
19
- end
31
+ # external redirect
32
+ def redirect_to(url)
33
+ throw :halt, [302, {"location" => url}, []]
34
+ end
20
35
 
21
- def redirect(location)
22
- throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
23
- end
36
+ def header(key, value)
37
+ env["response_headers"][key] = value.to_s
38
+ end
24
39
 
25
- def params
26
- indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
40
+ # internal redirect
41
+ def redirect(location)
42
+ throw :halt, [302, {"location" => "#{request.base_url}#{location}"}, []]
43
+ end
27
44
 
28
- indifferent_hash.merge! request.params
29
- route_params.each { |k, v| indifferent_hash[k.to_s] = v }
45
+ def reload_page
46
+ current_location = request.referer.gsub(request.base_url, "")
47
+ redirect current_location
48
+ end
30
49
 
31
- indifferent_hash
32
- end
50
+ # stuff after ? or form input
51
+ # uses String keys, no Symbols!
52
+ def url_params(key)
53
+ warn { "URL parameter `#{key}` should be accessed via String, not Symbol (at #{caller(3..3).first})" } if key.is_a?(Symbol)
54
+ request.params[key.to_s]
55
+ end
33
56
 
34
- def route_params
35
- env[WebRouter::ROUTE_PARAMS]
36
- end
57
+ # variables embedded in path, `/metrics/:name`
58
+ # uses Symbol keys, no Strings!
59
+ def route_params(key)
60
+ warn { "Route parameter `#{key}` should be accessed via Symbol, not String (at #{caller(3..3).first})" } if key.is_a?(String)
61
+ env["rack.route_params"][key.to_sym]
62
+ end
37
63
 
38
- def session
39
- env[RACK_SESSION]
40
- end
64
+ def params
65
+ warn { "Direct access to Rack parameters is discouraged, use `url_params` or `route_params` (at #{caller(3..3).first})" }
66
+ request.params
67
+ end
41
68
 
42
- def erb(content, options = {})
43
- if content.is_a? Symbol
44
- unless respond_to?(:"_erb_#{content}")
45
- src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
46
- WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
47
- def _erb_#{content}
48
- #{src}
49
- end
50
- RUBY
51
- end
69
+ def session
70
+ env["rack.session"] || fail(<<~EOM)
71
+ Sidekiq::Web needs a valid Rack session. If this is a Rails app, make
72
+ sure you mount Sidekiq::Web *inside* your application routes:
73
+
74
+
75
+ Rails.application.routes.draw do
76
+ mount Sidekiq::Web => "/sidekiq"
77
+ ....
78
+ end
79
+
80
+
81
+ If this is a Rails app in API mode, you need to enable sessions.
82
+
83
+ https://guides.rubyonrails.org/api_app.html#using-session-middlewares
84
+
85
+ If this is a bare Rack app, use a session middleware before Sidekiq::Web:
86
+
87
+ # first, use IRB to create a shared secret key for sessions and commit it
88
+ require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) }
89
+
90
+ # now use the secret with a session cookie middleware
91
+ use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400
92
+ run Sidekiq::Web
93
+
94
+ EOM
52
95
  end
53
96
 
54
- if @_erb
55
- _erb(content, options[:locals])
56
- else
57
- @_erb = true
58
- content = _erb(content, options[:locals])
97
+ def logger
98
+ Sidekiq.logger
99
+ end
59
100
 
60
- _render { content }
101
+ # flash { "Some message to show on redirect" }
102
+ def flash
103
+ msg = yield
104
+ logger.info msg
105
+ session[:skq_flash] = msg
61
106
  end
62
- end
63
107
 
64
- def render(engine, content, options = {})
65
- raise "Only erb templates are supported" if engine != :erb
108
+ def flash?
109
+ session&.[](:skq_flash)
110
+ end
66
111
 
67
- erb(content, options)
68
- end
112
+ def get_flash
113
+ @flash ||= session.delete(:skq_flash)
114
+ end
69
115
 
70
- def json(payload)
71
- [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
72
- end
116
+ def erb(content, options = {})
117
+ if content.is_a? Symbol
118
+ unless respond_to?(:"_erb_#{content}")
119
+ views = options[:views] || Web.views
120
+ filename = "#{views}/#{content}.erb"
121
+ src = ERB.new(File.read(filename)).src
122
+
123
+ # Need to use lineno less by 1 because erb generates a
124
+ # comment before the source code.
125
+ Action.class_eval <<-RUBY, filename, -1 # standard:disable Style/EvalWithLocation
126
+ def _erb_#{content}
127
+ #{src}
128
+ end
129
+ RUBY
130
+ end
131
+ end
73
132
 
74
- def initialize(env, block)
75
- @_erb = false
76
- @env = env
77
- @block = block
78
- @files ||= {}
79
- end
133
+ if @_erb
134
+ _erb(content, options[:locals])
135
+ else
136
+ @_erb = true
137
+ content = _erb(content, options[:locals])
80
138
 
81
- private
139
+ _render { content }
140
+ end
141
+ end
142
+
143
+ def render(engine, content, options = {})
144
+ raise "Only erb templates are supported" if engine != :erb
145
+
146
+ erb(content, options)
147
+ end
148
+
149
+ def json(payload)
150
+ [200,
151
+ {"content-type" => "application/json", "cache-control" => "private, no-store"},
152
+ [Sidekiq.dump_json(payload)]]
153
+ end
82
154
 
83
- def _erb(file, locals)
84
- locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
155
+ private
85
156
 
86
- if file.is_a?(String)
87
- ERB.new(file).result(binding)
88
- else
89
- send(:"_erb_#{file}")
157
+ def warn
158
+ Sidekiq.logger.warn yield
90
159
  end
160
+
161
+ def _erb(file, locals)
162
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
163
+
164
+ if file.is_a?(String)
165
+ ERB.new(file).result(binding)
166
+ else
167
+ send(:"_erb_#{file}")
168
+ end
169
+ end
170
+
171
+ class_eval <<-RUBY, ::Sidekiq::Web::LAYOUT, -1 # standard:disable Style/EvalWithLocation
172
+ def _render
173
+ #{ERB.new(File.read(::Sidekiq::Web::LAYOUT)).src}
174
+ end
175
+ RUBY
91
176
  end
92
177
  end
93
178
  end