sidekiq 6.4.2 → 6.5.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +35 -0
  3. data/bin/sidekiqload +15 -3
  4. data/lib/sidekiq/api.rb +160 -32
  5. data/lib/sidekiq/cli.rb +34 -32
  6. data/lib/sidekiq/client.rb +4 -4
  7. data/lib/sidekiq/component.rb +65 -0
  8. data/lib/sidekiq/delay.rb +1 -1
  9. data/lib/sidekiq/fetch.rb +16 -14
  10. data/lib/sidekiq/job_retry.rb +50 -34
  11. data/lib/sidekiq/job_util.rb +7 -3
  12. data/lib/sidekiq/launcher.rb +22 -19
  13. data/lib/sidekiq/logger.rb +1 -1
  14. data/lib/sidekiq/manager.rb +23 -20
  15. data/lib/sidekiq/metrics/deploy.rb +47 -0
  16. data/lib/sidekiq/metrics/query.rb +124 -0
  17. data/lib/sidekiq/metrics/shared.rb +94 -0
  18. data/lib/sidekiq/metrics/tracking.rb +134 -0
  19. data/lib/sidekiq/middleware/chain.rb +82 -38
  20. data/lib/sidekiq/middleware/current_attributes.rb +10 -4
  21. data/lib/sidekiq/middleware/i18n.rb +2 -0
  22. data/lib/sidekiq/middleware/modules.rb +21 -0
  23. data/lib/sidekiq/paginator.rb +2 -2
  24. data/lib/sidekiq/processor.rb +13 -13
  25. data/lib/sidekiq/rails.rb +5 -5
  26. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  27. data/lib/sidekiq/redis_connection.rb +80 -47
  28. data/lib/sidekiq/ring_buffer.rb +29 -0
  29. data/lib/sidekiq/scheduled.rb +11 -10
  30. data/lib/sidekiq/testing.rb +1 -1
  31. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  32. data/lib/sidekiq/version.rb +1 -1
  33. data/lib/sidekiq/web/application.rb +13 -0
  34. data/lib/sidekiq/web/helpers.rb +25 -2
  35. data/lib/sidekiq/web.rb +4 -0
  36. data/lib/sidekiq/worker.rb +2 -1
  37. data/lib/sidekiq.rb +87 -18
  38. data/sidekiq.gemspec +1 -1
  39. data/web/assets/javascripts/application.js +1 -1
  40. data/web/assets/javascripts/dashboard.js +0 -17
  41. data/web/assets/javascripts/graph.js +16 -0
  42. data/web/locales/en.yml +4 -0
  43. data/web/locales/pt-br.yml +27 -9
  44. data/web/views/_nav.erb +1 -1
  45. data/web/views/busy.erb +1 -1
  46. data/web/views/dashboard.erb +1 -0
  47. data/web/views/metrics.erb +59 -0
  48. data/web/views/metrics_for_job.erb +92 -0
  49. data/web/views/queue.erb +5 -1
  50. metadata +16 -6
  51. data/lib/sidekiq/exception_handler.rb +0 -27
  52. data/lib/sidekiq/util.rb +0 -108
data/web/locales/en.yml CHANGED
@@ -84,3 +84,7 @@ en: # <---- change this to your locale code
84
84
  Latency: Latency
85
85
  Pause: Pause
86
86
  Unpause: Unpause
87
+ Metrics: Metrics
88
+ NoDataFound: No data found
89
+ ExecutionTime: Execution Time
90
+ Context: Context
@@ -8,6 +8,7 @@
8
8
  History: Histórico
9
9
  Busy: Ocupados
10
10
  Processed: Processados
11
+ Utilization: Utilização
11
12
  Failed: Falhas
12
13
  Scheduled: Agendados
13
14
  Retries: Tentativas
@@ -26,18 +27,20 @@
26
27
  Delete: Apagar
27
28
  AddToQueue: Adicionar à fila
28
29
  AreYouSureDeleteJob: Deseja deletar esta tarefa?
29
- AreYouSureDeleteQueue: Deseja deletar a %{queue} fila?
30
+ AreYouSureDeleteQueue: Deseja deletar a fila %{queue}? Isso irá deletar todas as tarefas desta fila.
30
31
  Queues: Filas
31
32
  Size: Tamanho
32
33
  Actions: Ações
33
34
  NextRetry: Próxima Tentativa
34
35
  RetryCount: Número de Tentativas
35
36
  RetryNow: Tentar novamente agora
37
+ Kill: Matar
36
38
  LastRetry: Última tentativa
37
39
  OriginallyFailed: Falhou originalmente
38
40
  AreYouSure: Tem certeza?
39
41
  DeleteAll: Apagar tudo
40
42
  RetryAll: Tentar tudo novamente
43
+ KillAll: Matar todas
41
44
  NoRetriesFound: Nenhuma tentativa encontrada
42
45
  Error: Erro
43
46
  ErrorClass: Classe de erro
@@ -58,11 +61,26 @@
58
61
  OneMonth: 1 mês
59
62
  ThreeMonths: 3 meses
60
63
  SixMonths: 6 meses
61
- Failures : Falhas
62
- DeadJobs : Tarefas mortas
63
- NoDeadJobsFound : Nenhuma tarefa morta foi encontrada
64
- Dead : Morta
65
- Processes : Processos
66
- Thread : Thread
67
- Threads : Threads
68
- Jobs : Tarefas
64
+ Failures: Falhas
65
+ DeadJobs: Tarefas mortas
66
+ NoDeadJobsFound: Nenhuma tarefa morta foi encontrada
67
+ Dead: Morta
68
+ Process: Processo
69
+ Processes: Processos
70
+ Name: Nome
71
+ Thread: Thread
72
+ Threads: Threads
73
+ Jobs: Tarefas
74
+ Paused: Pausado
75
+ Stop: Parar
76
+ Quiet: Silenciar
77
+ StopAll: Parar Todos
78
+ QuietAll: Silenciar Todos
79
+ PollingInterval: Intervalo de Polling
80
+ Plugins: Plug-ins
81
+ NotYetEnqueued: Ainda não enfileirado
82
+ CreatedAt: Criado em
83
+ BackToApp: De volta ao aplicativo
84
+ Latency: Latência
85
+ Pause: Pausar
86
+ Unpause: Despausar
data/web/views/_nav.erb CHANGED
@@ -1,7 +1,7 @@
1
1
  <div class="navbar navbar-default navbar-fixed-top">
2
2
  <div class="container-fluid">
3
3
  <div class="navbar-header" data-navbar="static">
4
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-menu">
4
+ <button type="button" class="navbar-toggle collapsed" data-toggle="navbar-menu" data-target="#navbar-menu">
5
5
  <span class="icon-bar"></span>
6
6
  <span class="icon-bar"></span>
7
7
  <span class="icon-bar"></span>
data/web/views/busy.erb CHANGED
@@ -54,7 +54,7 @@
54
54
  <th>&nbsp;</th>
55
55
  </thead>
56
56
  <% lead = processes.leader %>
57
- <% processes.each do |process| %>
57
+ <% sorted_processes.each do |process| %>
58
58
  <tr>
59
59
  <td class="box">
60
60
  <%= "#{process['hostname']}:#{process['pid']}" %>
@@ -1,3 +1,4 @@
1
+ <script type="text/javascript" src="<%= root_path %>javascripts/graph.js"></script>
1
2
  <script type="text/javascript" src="<%= root_path %>javascripts/dashboard.js"></script>
2
3
  <div class= "dashboard clearfix">
3
4
  <h3 >
@@ -0,0 +1,59 @@
1
+
2
+ <h1><%= t('Metrics') %></h1>
3
+
4
+ <h3>Top Jobs by Processed Count</h3>
5
+ <% top = @resultset[:top_classes] %>
6
+
7
+ <% topp = top["p"]&.first(10) %>
8
+ <div class="table_container">
9
+ <table class="table table-bordered table-striped table-hover">
10
+ <tbody>
11
+ <tr>
12
+ <th><%= t('Name') %></th>
13
+ <th><%= t('Processed') %></th>
14
+ <th><%= t('ExecutionTime') %></th>
15
+ </tr>
16
+ <% if topp %>
17
+ <% topp.each do |kls, val| %>
18
+ <tr>
19
+ <td><code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code></td>
20
+ <td><%= val %></td>
21
+ <td><%= top.dig("ms", kls) %></td>
22
+ </tr>
23
+ <% end %>
24
+ <% else %>
25
+ <tr><td colspan=3><%= t("NoDataFound") %></td></tr>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ </div>
30
+
31
+ <h3>Top Jobs by Execution Time</h3>
32
+
33
+ <% topms = top["ms"]&.first(10) %>
34
+ <div class="table_container">
35
+ <table class="table table-bordered table-striped table-hover">
36
+ <tbody>
37
+ <tr>
38
+ <th><%= t('Name') %></th>
39
+ <th><%= t('Processed') %></th>
40
+ <th><%= t('ExecutionTime') %></th>
41
+ </tr>
42
+ <% if topms %>
43
+ <% topms.each do |kls, val| %>
44
+ <tr>
45
+ <td><code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code></td>
46
+ <td><%= top.dig("p", kls) %></td>
47
+ <td><%= val %></td>
48
+ </tr>
49
+ <% end %>
50
+ <% else %>
51
+ <tr><td colspan=3><%= t("NoDataFound") %></td></tr>
52
+ <% end %>
53
+ </tbody>
54
+ </table>
55
+ </div>
56
+
57
+ <p>
58
+ Data from <%= @resultset[:starts_at] %> to <%= @resultset[:ends_at] %>
59
+ </p>
@@ -0,0 +1,92 @@
1
+
2
+ <h2><%= t('Metrics') %> / <%= h @name %></h2>
3
+
4
+ <div class="row chart">
5
+ <div id="realtime" data-processed-label="<%= t('Processed') %>" data-failed-label="<%= t('Failed') %>"></div>
6
+ </div>
7
+
8
+ <% data = @resultset[:data] %>
9
+ <div class="table_container">
10
+ <table class="table table-bordered table-striped table-hover">
11
+ <tbody>
12
+ <tr>
13
+ <th><%= t('Time') %></th>
14
+ <th><%= t('Processed') %></th>
15
+ <th><%= t('ExecutionTime') %></th>
16
+ <th><%= t('Failed') %></th>
17
+ <th><%= t('Deploy') %></th>
18
+ <th><%= t('Histogram') %></th>
19
+ </tr>
20
+ <% data.each do |hash| %>
21
+ <tr><td><%= hash[:time] %></td><td><%= hash[:p] %></td><td><%= hash[:ms] %></td><td><%= hash[:f] %></td><td><%= hash[:mark] %></td><td><%= hash[:hist] %></td></tr>
22
+ <% end %>
23
+ </tbody>
24
+ </table>
25
+ </div>
26
+
27
+ <p>
28
+ Data from <%= @resultset[:starts_at] %> to <%= @resultset[:ends_at] %>
29
+ </p>
30
+
31
+ <% atad = data.reverse %>
32
+ <script type="text/javascript" src="<%= root_path %>javascripts/graph.js"></script>
33
+ <script>
34
+ var palette = new Rickshaw.Color.Palette();
35
+ var data = [ {
36
+ name: "Processed",
37
+ color: palette.color(),
38
+ data: [ <% atad.each do |hash| %>
39
+ { x: <%= hash[:epoch] %>, y: <%= hash[:p] %> },
40
+ <% end %> ]
41
+ }, {
42
+ name: "Failed",
43
+ color: palette.color(),
44
+ data: [ <% atad.each do |hash| %>
45
+ { x: <%= hash[:epoch] %>, y: <%= hash[:f] %> },
46
+ <% end %>
47
+ ]
48
+ }, {
49
+ name: "Execution Time",
50
+ color: palette.color(),
51
+ data: [ <% atad.each do |hash| %>
52
+ { x: <%= hash[:epoch] %>, y: <%= hash[:ms] %> },
53
+ <% end %>
54
+ ]
55
+ } ];
56
+
57
+ // TODO What to do with this? Minutely hover detail with a histogram bar chart?
58
+ var histogramData = [ <% atad.each do |hash| %>
59
+ { x: <%= hash[:epoch] %>, hist: <%= hash[:hist] %> },
60
+ <% end %> ]
61
+ var histogramLabels = <%= Sidekiq::Metrics::Histogram::LABELS.inspect %>;
62
+
63
+ var timeInterval = 60000;
64
+ var graphElement = document.getElementById("realtime");
65
+
66
+ var graph = new Rickshaw.Graph({
67
+ element: graphElement,
68
+ width: responsiveWidth(),
69
+ renderer: 'line',
70
+ interpolation: 'linear',
71
+ series: data,
72
+ });
73
+ var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
74
+
75
+ var y_axis = new Rickshaw.Graph.Axis.Y( {
76
+ graph: graph,
77
+ tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
78
+ ticksTreatment: 'glow'
79
+ });
80
+
81
+ graph.render();
82
+
83
+ var hoverDetail = new Rickshaw.Graph.HoverDetail( {
84
+ graph: graph,
85
+ // formatter: function(series, x, y) {
86
+ // var date = '<span class="date">' + new Date(x * 1000).toUTCString() + '</span>';
87
+ // var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
88
+ // var content = swatch + series.name + ": " + parseInt(y) + '<br>' + date;
89
+ // return content;
90
+ // }
91
+ } );
92
+ </script>
data/web/views/queue.erb CHANGED
@@ -18,6 +18,7 @@
18
18
  <th><a href="<%= url %>?direction=<%= params[:direction] == 'asc' ? 'desc' : 'asc' %>"># <%= sort_direction_label %></a></th>
19
19
  <th><%= t('Job') %></th>
20
20
  <th><%= t('Arguments') %></th>
21
+ <th><%= t('Context') %></th>
21
22
  <th></th>
22
23
  </thead>
23
24
  <% @jobs.each_with_index do |job, index| %>
@@ -35,12 +36,15 @@
35
36
  <% a = job.display_args %>
36
37
  <% if a.inspect.size > 100 %>
37
38
  <span id="job_<%= index %>"><%= h(a.inspect[0..100]) + "... " %></span>
38
- <button data-toggle="job_<%= index %>" class="btn btn-default btn-xs"><%= t('ShowAll') %></button>
39
+ <button data-toggle="job_<%= index %>_full" class="btn btn-default btn-xs"><%= t('ShowAll') %></button>
39
40
  <div class="toggle" id="job_<%= index %>_full"><%= display_args(a) %></div>
40
41
  <% else %>
41
42
  <%= display_args(job.display_args) %>
42
43
  <% end %>
43
44
  </td>
45
+ <td>
46
+ <%= h(job["cattr"].inspect) if job["cattr"]&.any? %>
47
+ </td>
44
48
  <td>
45
49
  <form action="<%= root_path %>queues/<%= CGI.escape(@name) %>/delete" method="post">
46
50
  <%= csrf_tag %>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.4.2
4
+ version: 6.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-19 00:00:00.000000000 Z
11
+ date: 2022-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: 4.5.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: 4.5.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: connection_pool
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -75,8 +75,8 @@ files:
75
75
  - lib/sidekiq/api.rb
76
76
  - lib/sidekiq/cli.rb
77
77
  - lib/sidekiq/client.rb
78
+ - lib/sidekiq/component.rb
78
79
  - lib/sidekiq/delay.rb
79
- - lib/sidekiq/exception_handler.rb
80
80
  - lib/sidekiq/extensions/action_mailer.rb
81
81
  - lib/sidekiq/extensions/active_record.rb
82
82
  - lib/sidekiq/extensions/class_methods.rb
@@ -89,20 +89,27 @@ files:
89
89
  - lib/sidekiq/launcher.rb
90
90
  - lib/sidekiq/logger.rb
91
91
  - lib/sidekiq/manager.rb
92
+ - lib/sidekiq/metrics/deploy.rb
93
+ - lib/sidekiq/metrics/query.rb
94
+ - lib/sidekiq/metrics/shared.rb
95
+ - lib/sidekiq/metrics/tracking.rb
92
96
  - lib/sidekiq/middleware/chain.rb
93
97
  - lib/sidekiq/middleware/current_attributes.rb
94
98
  - lib/sidekiq/middleware/i18n.rb
99
+ - lib/sidekiq/middleware/modules.rb
95
100
  - lib/sidekiq/monitor.rb
96
101
  - lib/sidekiq/paginator.rb
97
102
  - lib/sidekiq/processor.rb
98
103
  - lib/sidekiq/rails.rb
104
+ - lib/sidekiq/redis_client_adapter.rb
99
105
  - lib/sidekiq/redis_connection.rb
106
+ - lib/sidekiq/ring_buffer.rb
100
107
  - lib/sidekiq/scheduled.rb
101
108
  - lib/sidekiq/sd_notify.rb
102
109
  - lib/sidekiq/systemd.rb
103
110
  - lib/sidekiq/testing.rb
104
111
  - lib/sidekiq/testing/inline.rb
105
- - lib/sidekiq/util.rb
112
+ - lib/sidekiq/transaction_aware_client.rb
106
113
  - lib/sidekiq/version.rb
107
114
  - lib/sidekiq/web.rb
108
115
  - lib/sidekiq/web/action.rb
@@ -118,6 +125,7 @@ files:
118
125
  - web/assets/images/status.png
119
126
  - web/assets/javascripts/application.js
120
127
  - web/assets/javascripts/dashboard.js
128
+ - web/assets/javascripts/graph.js
121
129
  - web/assets/stylesheets/application-dark.css
122
130
  - web/assets/stylesheets/application-rtl.css
123
131
  - web/assets/stylesheets/application.css
@@ -162,6 +170,8 @@ files:
162
170
  - web/views/dashboard.erb
163
171
  - web/views/dead.erb
164
172
  - web/views/layout.erb
173
+ - web/views/metrics.erb
174
+ - web/views/metrics_for_job.erb
165
175
  - web/views/morgue.erb
166
176
  - web/views/queue.erb
167
177
  - web/views/queues.erb
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq"
4
-
5
- module Sidekiq
6
- module ExceptionHandler
7
- class Logger
8
- def call(ex, ctx)
9
- Sidekiq.logger.warn(Sidekiq.dump_json(ctx)) unless ctx.empty?
10
- Sidekiq.logger.warn("#{ex.class.name}: #{ex.message}")
11
- Sidekiq.logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
12
- end
13
-
14
- Sidekiq.error_handlers << Sidekiq::ExceptionHandler::Logger.new
15
- end
16
-
17
- def handle_exception(ex, ctx = {})
18
- Sidekiq.error_handlers.each do |handler|
19
- handler.call(ex, ctx)
20
- rescue => ex
21
- Sidekiq.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
22
- Sidekiq.logger.error ex
23
- Sidekiq.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
24
- end
25
- end
26
- end
27
- end
data/lib/sidekiq/util.rb DELETED
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "forwardable"
4
- require "socket"
5
- require "securerandom"
6
- require "sidekiq/exception_handler"
7
-
8
- module Sidekiq
9
- ##
10
- # This module is part of Sidekiq core and not intended for extensions.
11
- #
12
-
13
- class RingBuffer
14
- include Enumerable
15
- extend Forwardable
16
- def_delegators :@buf, :[], :each, :size
17
-
18
- def initialize(size, default = 0)
19
- @size = size
20
- @buf = Array.new(size, default)
21
- @index = 0
22
- end
23
-
24
- def <<(element)
25
- @buf[@index % @size] = element
26
- @index += 1
27
- element
28
- end
29
-
30
- def buffer
31
- @buf
32
- end
33
-
34
- def reset(default = 0)
35
- @buf.fill(default)
36
- end
37
- end
38
-
39
- module Util
40
- include ExceptionHandler
41
-
42
- # hack for quicker development / testing environment #2774
43
- PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
44
-
45
- # Wait for the orblock to be true or the deadline passed.
46
- def wait_for(deadline, &condblock)
47
- remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
48
- while remaining > PAUSE_TIME
49
- return if condblock.call
50
- sleep PAUSE_TIME
51
- remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
52
- end
53
- end
54
-
55
- def watchdog(last_words)
56
- yield
57
- rescue Exception => ex
58
- handle_exception(ex, {context: last_words})
59
- raise ex
60
- end
61
-
62
- def safe_thread(name, &block)
63
- Thread.new do
64
- Thread.current.name = name
65
- watchdog(name, &block)
66
- end
67
- end
68
-
69
- def logger
70
- Sidekiq.logger
71
- end
72
-
73
- def redis(&block)
74
- Sidekiq.redis(&block)
75
- end
76
-
77
- def tid
78
- Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
79
- end
80
-
81
- def hostname
82
- ENV["DYNO"] || Socket.gethostname
83
- end
84
-
85
- def process_nonce
86
- @@process_nonce ||= SecureRandom.hex(6)
87
- end
88
-
89
- def identity
90
- @@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}"
91
- end
92
-
93
- def fire_event(event, options = {})
94
- reverse = options[:reverse]
95
- reraise = options[:reraise]
96
-
97
- arr = Sidekiq.options[:lifecycle_events][event]
98
- arr.reverse! if reverse
99
- arr.each do |block|
100
- block.call
101
- rescue => ex
102
- handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event})
103
- raise ex if reraise
104
- end
105
- arr.clear
106
- end
107
- end
108
- end