sidekiq 7.1.6 → 7.2.4

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +68 -0
  3. data/README.md +2 -2
  4. data/bin/multi_queue_bench +271 -0
  5. data/lib/sidekiq/api.rb +77 -11
  6. data/lib/sidekiq/cli.rb +3 -1
  7. data/lib/sidekiq/config.rb +4 -4
  8. data/lib/sidekiq/deploy.rb +2 -2
  9. data/lib/sidekiq/job.rb +1 -1
  10. data/lib/sidekiq/job_retry.rb +3 -3
  11. data/lib/sidekiq/launcher.rb +6 -4
  12. data/lib/sidekiq/logger.rb +1 -1
  13. data/lib/sidekiq/metrics/query.rb +4 -1
  14. data/lib/sidekiq/metrics/tracking.rb +7 -3
  15. data/lib/sidekiq/middleware/current_attributes.rb +1 -1
  16. data/lib/sidekiq/paginator.rb +2 -2
  17. data/lib/sidekiq/processor.rb +1 -1
  18. data/lib/sidekiq/rails.rb +7 -3
  19. data/lib/sidekiq/redis_client_adapter.rb +16 -0
  20. data/lib/sidekiq/redis_connection.rb +3 -6
  21. data/lib/sidekiq/scheduled.rb +2 -2
  22. data/lib/sidekiq/testing.rb +9 -3
  23. data/lib/sidekiq/transaction_aware_client.rb +7 -0
  24. data/lib/sidekiq/version.rb +1 -1
  25. data/lib/sidekiq/web/action.rb +5 -0
  26. data/lib/sidekiq/web/application.rb +32 -4
  27. data/lib/sidekiq/web/csrf_protection.rb +8 -5
  28. data/lib/sidekiq/web/helpers.rb +14 -15
  29. data/sidekiq.gemspec +1 -1
  30. data/web/assets/javascripts/application.js +21 -0
  31. data/web/assets/javascripts/dashboard-charts.js +14 -0
  32. data/web/assets/javascripts/dashboard.js +7 -9
  33. data/web/assets/javascripts/metrics.js +34 -0
  34. data/web/assets/stylesheets/application-rtl.css +10 -0
  35. data/web/assets/stylesheets/application.css +22 -0
  36. data/web/views/_footer.erb +13 -1
  37. data/web/views/_metrics_period_select.erb +1 -1
  38. data/web/views/_summary.erb +7 -7
  39. data/web/views/busy.erb +7 -7
  40. data/web/views/dashboard.erb +23 -33
  41. data/web/views/filtering.erb +4 -4
  42. data/web/views/metrics.erb +36 -27
  43. data/web/views/metrics_for_job.erb +26 -35
  44. data/web/views/queues.erb +6 -2
  45. metadata +5 -4
@@ -1,39 +1,39 @@
1
1
  <ul class="list-unstyled summary row">
2
2
  <li class="processed col-sm-1">
3
- <span id="txtProcessed" class="count"><%= number_with_delimiter(stats.processed) %></span>
3
+ <span id="txtProcessed" class="count" data-nwp><%= stats.processed %></span>
4
4
  <span class="desc"><%= t('Processed') %></span>
5
5
  </li>
6
6
  <li class="failed col-sm-1">
7
- <span id="txtFailed" class="count"><%= number_with_delimiter(stats.failed) %></span>
7
+ <span id="txtFailed" class="count" data-nwp><%= stats.failed %></span>
8
8
  <span class="desc"><%= t('Failed') %></span>
9
9
  </li>
10
10
  <li class="busy col-sm-1">
11
11
  <a href="<%= root_path %>busy">
12
- <span id="txtBusy" class="count"><%= number_with_delimiter(workset.size) %></span>
12
+ <span id="txtBusy" class="count" data-nwp><%= workset.size %></span>
13
13
  <span class="desc"><%= t('Busy') %></span>
14
14
  </a>
15
15
  </li>
16
16
  <li class="enqueued col-sm-1">
17
17
  <a href="<%= root_path %>queues">
18
- <span id="txtEnqueued" class="count"><%= number_with_delimiter(stats.enqueued) %></span>
18
+ <span id="txtEnqueued" class="count" data-nwp><%= stats.enqueued %></span>
19
19
  <span class="desc"><%= t('Enqueued') %></span>
20
20
  </a>
21
21
  </li>
22
22
  <li class="retries col-sm-1">
23
23
  <a href="<%= root_path %>retries">
24
- <span id="txtRetries" class="count"><%= number_with_delimiter(stats.retry_size) %></span>
24
+ <span id="txtRetries" class="count" data-nwp><%= stats.retry_size %></span>
25
25
  <span class="desc"><%= t('Retries') %></span>
26
26
  </a>
27
27
  </li>
28
28
  <li class="scheduled col-sm-1">
29
29
  <a href="<%= root_path %>scheduled">
30
- <span id="txtScheduled" class="count"><%= number_with_delimiter(stats.scheduled_size) %></span>
30
+ <span id="txtScheduled" class="count" data-nwp><%= stats.scheduled_size %></span>
31
31
  <span class="desc"><%= t('Scheduled') %></span>
32
32
  </a>
33
33
  </li>
34
34
  <li class="dead col-sm-1">
35
35
  <a href="<%= root_path %>morgue">
36
- <span id="txtDead" class="count"><%= number_with_delimiter(stats.dead_size) %></span>
36
+ <span id="txtDead" class="count" data-nwp><%= stats.dead_size %></span>
37
37
  <span class="desc"><%= t('Dead') %></span>
38
38
  </a>
39
39
  </li>
data/web/views/busy.erb CHANGED
@@ -86,9 +86,9 @@
86
86
  <% end %>
87
87
  </td>
88
88
  <td><%= relative_time(Time.at(process['started_at'])) %></td>
89
- <td><%= format_memory(process['rss'].to_i) %></td>
90
- <td><%= process['concurrency'] %></td>
91
- <td><%= process['busy'] %></td>
89
+ <td class="num"><%= format_memory(process['rss'].to_i) %></td>
90
+ <td class="num"><%= number_with_delimiter(process['concurrency']) %></td>
91
+ <td class="num"><%= number_with_delimiter(process['busy']) %></td>
92
92
  <td>
93
93
  <% unless process.embedded? %>
94
94
  <form method="POST">
@@ -125,14 +125,14 @@
125
125
  <th><%= t('Arguments') %></th>
126
126
  <th><%= t('Started') %></th>
127
127
  </thead>
128
- <% @workset.each do |process, thread, msg| %>
129
- <% job = Sidekiq::JobRecord.new(msg['payload']) %>
128
+ <% @workset.each do |process, thread, work| %>
129
+ <% job = work.job %>
130
130
  <tr>
131
131
  <td><%= process %></td>
132
132
  <td><%= thread %></td>
133
133
  <td><%= job.jid %></td>
134
134
  <td>
135
- <a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
135
+ <a href="<%= root_path %>queues/<%= work.queue %>"><%= work.queue %></a>
136
136
  </td>
137
137
  <td>
138
138
  <%= job.display_class %>
@@ -141,7 +141,7 @@
141
141
  <td>
142
142
  <div class="args"><%= display_args(job.display_args) %></div>
143
143
  </td>
144
- <td><%= relative_time(Time.at(msg['run_at'])) %></td>
144
+ <td><%= relative_time(work.run_at) %></td>
145
145
  </tr>
146
146
  <% end %>
147
147
  </table>
@@ -1,7 +1,3 @@
1
- <script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
2
- <script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
3
- <script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
4
- <script type="text/javascript" src="<%= root_path %>javascripts/dashboard-charts.js"></script>
5
1
  <script type="text/javascript" src="<%= root_path %>javascripts/dashboard.js"></script>
6
2
  <div class= "dashboard clearfix">
7
3
  <h3 >
@@ -20,26 +16,19 @@
20
16
  </div>
21
17
 
22
18
  <div class="row chart">
23
- <canvas id="realtime-chart"></canvas>
24
- <script>
25
- window.realtimeChart = new RealtimeChart(
26
- document.getElementById("realtime-chart"),
27
- <%= Sidekiq.dump_json({
28
- processedLabel: t('Processed'),
29
- failedLabel: t('Failed'),
30
- labels: Array.new(50, ""),
31
- processed: Array.new(50),
32
- failed: Array.new(50),
33
- updateUrl: "#{root_path}stats",
34
- }) %>
35
- )
36
- </script>
19
+ <canvas id="realtime-chart">
20
+ <%= to_json({
21
+ processedLabel: t('Processed'),
22
+ failedLabel: t('Failed'),
23
+ labels: Array.new(50, ""),
24
+ processed: Array.new(50),
25
+ failed: Array.new(50),
26
+ updateUrl: "#{root_path}stats",
27
+ }) %>
28
+ </canvas>
37
29
 
38
30
  <!-- start with a space in the legend so the height doesn't change when we add content dynamically -->
39
31
  <div id="realtime-legend">&nbsp;</div>
40
- <script>
41
- realtimeChart.registerLegend(document.getElementById("realtime-legend"))
42
- </script>
43
32
  </div>
44
33
 
45
34
  <div class="row header">
@@ -55,18 +44,14 @@
55
44
  <a href="<%= root_path %>?days=180" class="history-graph <%= "active" if params[:days] == "180" %>"><%= t('SixMonths') %></a>
56
45
  </div>
57
46
 
58
- <canvas id="history-chart"></canvas>
59
- <script>
60
- window.historyChart = new DashboardChart(
61
- document.getElementById("history-chart"),
62
- <%= Sidekiq.dump_json({
63
- processedLabel: t('Processed'),
64
- failedLabel: t('Failed'),
65
- processed: @processed_history.to_a.reverse,
66
- failed: @failed_history.to_a.reverse,
67
- }) %>
68
- )
69
- </script>
47
+ <canvas id="history-chart">
48
+ <%= to_json({
49
+ processedLabel: t('Processed'),
50
+ failedLabel: t('Failed'),
51
+ processed: @processed_history.to_a.reverse,
52
+ failed: @failed_history.to_a.reverse,
53
+ }) %>
54
+ </canvas>
70
55
  </div>
71
56
 
72
57
  <br/>
@@ -113,3 +98,8 @@
113
98
  <% end %>
114
99
  </div>
115
100
  </div>
101
+
102
+ <script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
103
+ <script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
104
+ <script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
105
+ <script type="text/javascript" src="<%= root_path %>javascripts/dashboard-charts.js"></script>
@@ -1,7 +1,7 @@
1
- <div class="sm-col-3 pull-right" style="display: inline; margin: 25px 15px 0 0;">
2
- <%= t('Filter') %>:
3
- <form method="POST" action='<%= root_path %>filter/<%= which %>' style="display: inline-block">
1
+ <div>
2
+ <form method="post" class="form-inline" action='<%= root_path %>filter/<%= which %>'>
4
3
  <%= csrf_tag %>
5
- <input class="search" type="search" name="substr" value="<%= h params[:substr] %>" placeholder="<%= t('AnyJobContent') %>"/>
4
+ <label for="substr"><%= t('Filter') %></label>
5
+ <input class="search form-control" type="search" name="substr" value="<%= h params[:substr] %>" placeholder="<%= t('AnyJobContent') %>"/>
6
6
  </form>
7
7
  </div>
@@ -1,16 +1,29 @@
1
1
  <script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
2
2
  <script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
3
3
  <script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
4
- <script type="text/javascript" src="<%= root_path %>javascripts/metrics.js"></script>
5
4
 
6
5
  <div class="header-container">
7
6
  <div class="page-title-container">
8
7
  <h1><%= t('Metrics') %></h1>
9
-
10
8
  <a target="blank" href="https://github.com/sidekiq/sidekiq/wiki/Metrics"><span class="info-circle" title="Click to learn more about metrics">?</span></a>
11
9
  </div>
12
10
 
13
- <%= erb :_metrics_period_select, locals: { periods: @periods, period: @period, path: "#{root_path}metrics" } %>
11
+ <div>
12
+ <form id="metrics-form" class="form-inline" action="<%= root_path %>filter/metrics" method="post">
13
+ <%= csrf_tag %>
14
+ <label for="substr"><%= t('Filter') %></label>
15
+ <input id="class-filter" class="form-control" type="text" name="substr" placeholder="<%= t('Name') %>" value="<%= h params[:substr] %>">
16
+ <select id="period-selector" class="form-control" name="period">
17
+ <% @periods.each_key do |code| %>
18
+ <% if code == @period %>
19
+ <option selected value="<%= code %>"><%= code %></option>
20
+ <% else %>
21
+ <option value="<%= code %>"><%= code %></option>
22
+ <% end %>
23
+ <% end %>
24
+ </select>
25
+ </form>
26
+ </div>
14
27
  </div>
15
28
 
16
29
  <%
@@ -21,22 +34,17 @@
21
34
  %>
22
35
 
23
36
  <% if job_results.any? %>
24
- <canvas id="job-metrics-overview-chart"></canvas>
25
-
26
- <script>
27
- window.jobMetricsChart = new JobMetricsOverviewChart(
28
- document.getElementById("job-metrics-overview-chart"),
29
- <%= Sidekiq.dump_json({
30
- series: job_results.map { |(kls, jr)| [kls, jr.dig("series", "s")] }.to_h,
31
- marks: @query_result.marks.map { |m| [m.bucket, m.label] },
32
- labels: @query_result.buckets,
33
- visibleKls: visible_kls,
34
- yLabel: t('TotalExecutionTime'),
35
- units: t('Seconds').downcase,
36
- markLabel: t('Deploy'),
37
- }) %>
38
- )
39
- </script>
37
+ <canvas id="job-metrics-overview-chart">
38
+ <%= to_json({
39
+ series: job_results.map { |(kls, jr)| [kls, jr.dig("series", "s")] }.to_h,
40
+ marks: @query_result.marks.map { |m| [m.bucket, m.label] },
41
+ labels: @query_result.buckets,
42
+ visibleKls: visible_kls,
43
+ yLabel: t('TotalExecutionTime'),
44
+ units: t('Seconds').downcase,
45
+ markLabel: t('Deploy'),
46
+ }) %>
47
+ </canvas>
40
48
  <% end %>
41
49
 
42
50
  <div class="table_container">
@@ -46,8 +54,8 @@
46
54
  <th><%= t('Name') %></th>
47
55
  <th><%= t('Success') %></th>
48
56
  <th><%= t('Failure') %></th>
49
- <th><%= t('TotalExecutionTime') %></th>
50
- <th><%= t('AvgExecutionTime') %></th>
57
+ <th><%= t('TotalExecutionTime') %> (Seconds)</th>
58
+ <th><%= t('AvgExecutionTime') %> (Seconds)</th>
51
59
  </tr>
52
60
  <% if job_results.any? %>
53
61
  <% job_results.each_with_index do |(kls, jr), i| %>
@@ -64,12 +72,11 @@
64
72
  />
65
73
  <code><a href="<%= root_path %>metrics/<%= kls %>?period=<%= @period %>"><%= kls %></a></code>
66
74
  </div>
67
- <script>jobMetricsChart.registerSwatch("<%= id %>")</script>
68
75
  </td>
69
- <td><%= jr.dig("totals", "p") - jr.dig("totals", "f") %></td>
70
- <td><%= jr.dig("totals", "f") %></td>
71
- <td><%= jr.dig("totals", "s").round(2) %> seconds</td>
72
- <td><%= jr.total_avg("s").round(2) %> seconds</td>
76
+ <td class="num"><%= number_with_delimiter(jr.dig("totals", "p") - jr.dig("totals", "f")) %></td>
77
+ <td class="num"><%= number_with_delimiter(jr.dig("totals", "f")) %></td>
78
+ <td class="num"><%= number_with_delimiter(jr.dig("totals", "s"), precision: 2) %></td>
79
+ <td class="num"><%= number_with_delimiter(jr.total_avg("s"), precision: 2) %></td>
73
80
  </tr>
74
81
  <% end %>
75
82
  <% else %>
@@ -79,4 +86,6 @@
79
86
  </table>
80
87
  </div>
81
88
 
82
- <p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p>
89
+ <!--p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p-->
90
+
91
+ <script type="text/javascript" src="<%= root_path %>javascripts/metrics.js"></script>
@@ -1,7 +1,6 @@
1
1
  <script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
2
2
  <script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
3
3
  <script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
4
- <script type="text/javascript" src="<%= root_path %>javascripts/metrics.js"></script>
5
4
 
6
5
  <%
7
6
  job_result = @query_result.job_results[@name]
@@ -24,40 +23,30 @@
24
23
  <%= erb :_metrics_period_select, locals: { periods: @periods, period: @period, path: "#{root_path}metrics/#{@name}" } %>
25
24
  </div>
26
25
 
27
- <canvas id="hist-totals-chart"></canvas>
28
-
29
- <script>
30
- window.histTotalsChart = new HistTotalsChart(
31
- document.getElementById("hist-totals-chart"),
32
- <%= Sidekiq.dump_json({
33
- series: hist_totals,
34
- labels: bucket_labels,
35
- xLabel: t('ExecutionTime'),
36
- yLabel: t('Jobs'),
37
- units: t('Jobs').downcase,
38
- }) %>
39
- )
40
- </script>
41
-
42
- <canvas id="hist-bubble-chart"></canvas>
43
-
44
- <script>
45
- window.histBubbleChart = new HistBubbleChart(
46
- document.getElementById("hist-bubble-chart"),
47
- <%= Sidekiq.dump_json({
48
- hist: job_result.hist,
49
- marks: @query_result.marks.map { |m| [m.bucket, m.label] },
50
- labels: @query_result.buckets,
51
- histIntervals: bucket_intervals,
52
- yLabel: t('ExecutionTime'),
53
- markLabel: t('Deploy'),
54
- yUnits: t('Seconds').downcase,
55
- zUnits: t('Jobs').downcase,
56
- }) %>
57
- )
58
- </script>
59
-
60
- <p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p>
26
+ <canvas id="hist-totals-chart">
27
+ <%= to_json({
28
+ series: hist_totals,
29
+ labels: bucket_labels,
30
+ xLabel: t('ExecutionTime'),
31
+ yLabel: t('Jobs'),
32
+ units: t('Jobs').downcase,
33
+ }) %>
34
+ </canvas>
35
+
36
+ <canvas id="hist-bubble-chart">
37
+ <%= to_json({
38
+ hist: job_result.hist,
39
+ marks: @query_result.marks.map { |m| [m.bucket, m.label] },
40
+ labels: @query_result.buckets,
41
+ histIntervals: bucket_intervals,
42
+ yLabel: t('ExecutionTime'),
43
+ markLabel: t('Deploy'),
44
+ yUnits: t('Seconds').downcase,
45
+ zUnits: t('Jobs').downcase,
46
+ }) %>
47
+ </canvas>
48
+
49
+ <!--p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p-->
61
50
  <% else %>
62
51
  <h1>
63
52
  <a href="<%= root_path %>/metrics"><%= t('Metrics') %></a> /
@@ -66,3 +55,5 @@
66
55
 
67
56
  <div class="alert alert-success"><%= t('NoJobMetricsFound') %></div>
68
57
  <% end %>
58
+
59
+ <script type="text/javascript" src="<%= root_path %>javascripts/metrics.js"></script>
data/web/views/queues.erb CHANGED
@@ -18,8 +18,12 @@
18
18
  <span class="label label-danger"><%= t('Paused') %></span>
19
19
  <% end %>
20
20
  </td>
21
- <td><%= number_with_delimiter(queue.size) %> </td>
22
- <td><% queue_latency = queue.latency %><%= number_with_delimiter(queue_latency.round(2)) %><%= (queue_latency < 60) ? '' : " (#{relative_time(Time.at(Time.now.to_f - queue_latency))})" %> </td>
21
+ <td class="num"><%= number_with_delimiter(queue.size) %> </td>
22
+ <td class="num">
23
+ <% queue_latency = queue.latency %>
24
+ <%= (queue_latency < 60) ? '' : " (#{relative_time(Time.at(Time.now.to_f - queue_latency))})" %>
25
+ <%= number_with_delimiter(queue_latency, precision: 2) %>
26
+ </td>
23
27
  <td class="delete-confirm">
24
28
  <form action="<%=root_path %>queues/<%= CGI.escape(queue.name) %>" method="post">
25
29
  <%= 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: 7.1.6
4
+ version: 7.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-09 00:00:00.000000000 Z
11
+ date: 2024-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.14.0
19
+ version: 0.19.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: 0.14.0
26
+ version: 0.19.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: connection_pool
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -78,6 +78,7 @@ files:
78
78
  - Changes.md
79
79
  - LICENSE.txt
80
80
  - README.md
81
+ - bin/multi_queue_bench
81
82
  - bin/sidekiq
82
83
  - bin/sidekiqload
83
84
  - bin/sidekiqmon