sidekiq-failures 0.4.5 → 1.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3cf2e8b86ea584dc2d01d303a8b810a3527da318
4
- data.tar.gz: ea8731360ed096a6f6b885cb3f078a80bb96747e
2
+ SHA256:
3
+ metadata.gz: ba0a7d8ecb1ed1f847be0918723281d6c12d7f40a4780c089340cc8e687183f3
4
+ data.tar.gz: 10aca014769f8883c9de557bded7ac01287276924ad314ec1006d6d0e1c332bd
5
5
  SHA512:
6
- metadata.gz: dd021e8afcbd6a59c8d725d2954f7d45cbb50475b3c342b8e5d00533dd3c72594548d4fdb197e3d5a3cd51d158f000c050da57d353ef294c67bfe7880243dad8
7
- data.tar.gz: 422b175ead022b822ae08838a03365f22e6e4a0a2213ff8f9c2756ed3f41b14c58e9e7f950f32adce8d8f25e440c3a5a8b78753798a4162ddf8626cd9bb2c977
6
+ metadata.gz: 1bc85386b596a67b27e00b6c2efed3377f8377bb89dd4eb128336b0f1bf4150acd361c3be1f1ed8dce233710031f3bd9b17d09d4c85b7ee7673da67ba7649d89
7
+ data.tar.gz: 236381eb70f14564b3dd43fc715ad8ac3f5578973b4c20fb95f8f6cfcedadb82db922c1cb8eafed13e6c5189d5218ec0c959dbe559592413b727da2ef18fed25
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -0,0 +1,37 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ ruby: [2.6, 2.7, '3.0', 3.1, 3.4.3]
16
+ sidekiq: [4.2, 5.2, 6.2, 8.0.3]
17
+ services:
18
+ redis:
19
+ image: redis
20
+ options: >-
21
+ --health-cmd "redis-cli ping"
22
+ --health-interval 10s
23
+ --health-timeout 5s
24
+ --health-retries 5
25
+ ports:
26
+ - 6379:6379
27
+ env:
28
+ SIDEKIQ_VERSION: ~> ${{ matrix.sidekiq }}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - name: Set up Ruby
32
+ uses: ruby/setup-ruby@v1
33
+ with:
34
+ bundler-cache: true # 'bundle install' and cache gems
35
+ ruby-version: ${{ matrix.ruby }}
36
+ - name: Run tests
37
+ run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 1.1.0
4
+
5
+ * Add support for Sidekiq 8.x (#145 @navidemad)
6
+ * Fix nil exception in safe_relative_time (#152 @leedrum)
7
+
8
+ ## 1.0.4
9
+
10
+ * Sanitize failure text on the failure details page (#144 @mcasper)
11
+
12
+ ## 1.0.3
13
+
14
+ * Expand failure descriptions with pure JS (#141 @icyleaf)
15
+
16
+ ## 1.0.2
17
+
18
+ * Pass now required argument to Sidekiq's JobRetry.new (#140 @mcasper)
19
+
20
+ ## 1.0.1
21
+
22
+ * Add license config to the gemspec (#115 @reiz)
23
+ * Guard against failure error_message being `nil` (#122 @mcasper)
24
+ * Fix filtering failures with 0 results on Sidekiq Pro (#125 @substars)
25
+
26
+ ## 1.0.0
27
+
28
+ * WebUI improvements (@bbtfr)
29
+ * Use ActiveJob to display info when available (@dreyks)
30
+ * New locales (@ryohashimoto @gurgelrenan)
31
+ * Sidekiq 4 and higher compatibility (@davekrupinski )
32
+ * Sidekiq 5 fixes (@fidelisrafael)
33
+
3
34
  ## 0.4.5
4
35
 
5
36
  * Limit error message to 500 symbols (@antonzaytsev)
@@ -35,8 +66,8 @@
35
66
  ## 0.3.0
36
67
 
37
68
  * Bump sidekiq dependency to sidekiq >= 2.14.0
38
- * Remove slim templates and dependecy
39
- * Escape exception info when outputing to html
69
+ * Remove slim templates and dependency
70
+ * Escape exception info when outputting to html
40
71
  * Add `Sidekiq::Failures.reset_failures` helper method
41
72
  * Add `Sidekiq::Failures.count` helper method (@zanker)
42
73
  * Adhere to sidekiq approach of showing UTC times
@@ -59,8 +90,8 @@
59
90
  * Added processor identity to failure data (@krasnoukhov)
60
91
  * Handle Sidekiq::Shutdown exceptions (@krasnoukhov)
61
92
  * Add failures maximum count option (@mathieulaporte)
62
- * User Expception#message instead of Exception#to_s (@supaspoida)
63
- * Removed web depencies (@LongMan)
93
+ * User Exception#message instead of Exception#to_s (@supaspoida)
94
+ * Removed web dependencies (@LongMan)
64
95
  * Stop overloading find_template (@zquestz)
65
96
 
66
97
  ## 0.1.0
data/Gemfile CHANGED
@@ -4,3 +4,9 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'sidekiq', ENV['SIDEKIQ_VERSION'] if ENV['SIDEKIQ_VERSION']
7
+
8
+ # to test Pro-specific functionality, set SIDEKIQ_PRO_CREDS on `bundle install`
9
+ # and SIDEKIQ_PRO_VERSION on `bundle install` and `rake test`
10
+ source "https://#{ENV['SIDEKIQ_PRO_CREDS']}@enterprise.contribsys.com/" do
11
+ gem 'sidekiq-pro', ENV['SIDEKIQ_PRO_VERSION'] if ENV['SIDEKIQ_PRO_VERSION']
12
+ end if ENV['SIDEKIQ_PRO_VERSION']
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Sidekiq::Failures [![Build Status](https://secure.travis-ci.org/mhfs/sidekiq-failures.png)](http://travis-ci.org/mhfs/sidekiq-failures)
1
+ # Sidekiq::Failures ![Build Status](https://github.com/mhfs/sidekiq-failures/workflows/CI/badge.svg)
2
2
 
3
3
  Keeps track of Sidekiq failed jobs and adds a tab to the Web UI to let you browse
4
4
  them. Makes use of Sidekiq's custom tabs and middleware chain.
@@ -20,6 +20,8 @@ gem 'sidekiq-failures'
20
20
  Simply having the gem in your Gemfile is enough to get you started. Your failed
21
21
  jobs will be visible via a Failures tab in the Web UI.
22
22
 
23
+ If you have not previously used the Web UI, it is a part of the Sidekiq gem. [See Sidekiq's docs about Web UI here.](https://github.com/mperham/sidekiq/wiki/Monitoring#web-ui)
24
+
23
25
  ## Configuring
24
26
 
25
27
  ### Maximum Tracked Failures
@@ -125,18 +127,23 @@ influenced by `failures_max_count`.
125
127
  Sidekiq::Failures.count
126
128
  ```
127
129
 
128
- ### Reset Failures
130
+ ### Reset and clear Failures
131
+
132
+ Gives a convenient way of resetting Sidekiq Failure stored failed jobs programmatically.
133
+
134
+ ```ruby
135
+ Sidekiq::Failures.clear_failures
136
+ ```
129
137
 
130
- Gives a convenient way of reseting Sidekiq Failure stored failed jobs programmatically.
131
- Takes an options hash and if the `counter` key is present also resets Sidekiq own failed stats.
138
+ To reset Sidekiq own failed *stats*.
132
139
 
133
140
  ```ruby
134
- Sidekiq::Failures.reset_failures
141
+ Sidekiq::Failures.reset_failure_count
135
142
  ```
136
143
 
137
144
  ## Dependencies
138
145
 
139
- Depends on Sidekiq >= 2.16.0
146
+ Depends on Sidekiq >= 4.0.0
140
147
 
141
148
  ## Contributing
142
149
 
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+ ja:
3
+ FailedJobs: 失敗したジョブ
4
+ FailedAt: 失敗した日時
5
+ ResetCounter: カウンターをリセット
6
+ NoFailedJobsFound: 失敗したジョブはありません
@@ -0,0 +1,5 @@
1
+ pt-BR:
2
+ FailedJobs: Processos Falhos
3
+ FailedAt: Falhou em
4
+ ResetCounter: Resetar contador
5
+ NoFailedJobsFound: Nenhum Processo falho encontrado
@@ -0,0 +1,5 @@
1
+ zh-cn:
2
+ FailedJobs: 失败的任务
3
+ FailedAt: 失败时间
4
+ ResetCounter: 重置计数器
5
+ NoFailedJobsFound: 没有发现失败的任务
@@ -80,11 +80,12 @@ module Sidekiq
80
80
  end
81
81
 
82
82
  def retry_middleware
83
- @retry_middleware ||= Sidekiq::Middleware::Server::RetryJobs.new
83
+ @retry_middleware ||=
84
+ Sidekiq::Failures.retry_middleware_class.new(@config || {})
84
85
  end
85
86
 
86
87
  def default_max_retries
87
- Sidekiq::Middleware::Server::RetryJobs::DEFAULT_MAX_RETRY_ATTEMPTS
88
+ Sidekiq::Failures.retry_middleware_class::DEFAULT_MAX_RETRY_ATTEMPTS
88
89
  end
89
90
 
90
91
  def hostname
@@ -11,7 +11,14 @@ module Sidekiq
11
11
 
12
12
  def retry_failure
13
13
  Sidekiq.redis do |conn|
14
- results = conn.zrangebyscore(Sidekiq::Failures::LIST_KEY, score, score)
14
+ # from Redis v6.2.0, zrangebyscore is deprecated and zrange with BYSCORE is used
15
+ # option byscore is available from redis-rb v4.6.0
16
+ results = if Gem::Version.new(conn.info["redis_version"].to_s) >= Gem::Version.new('6.2.0') &&
17
+ (Gem.loaded_specs['redis'].nil? || Gem.loaded_specs['redis'].version >= Gem::Version.new('4.6.0'))
18
+ conn.zrange(Sidekiq::Failures::LIST_KEY, score.to_i, score.to_i, byscore: true)
19
+ else
20
+ conn.zrangebyscore(Sidekiq::Failures::LIST_KEY, score, score)
21
+ end
15
22
  conn.zremrangebyscore(Sidekiq::Failures::LIST_KEY, score, score)
16
23
  results.map do |message|
17
24
  msg = Sidekiq.load_json(message)
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Failures
3
- VERSION = "0.4.5"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -1,31 +1,39 @@
1
1
  <%= erb :_job_info, :locals => {:job => @failure, :type => :failure} %>
2
2
 
3
- <h3><%= t('Error') %></h3>
4
- <table class="error table table-bordered table-striped">
5
- <tbody>
6
- <tr>
7
- <th><%= t('ErrorClass') %></th>
8
- <td>
9
- <code><%= @failure['error_class'] %></code>
10
- </td>
11
- </tr>
12
- <tr>
13
- <th><%= t('ErrorMessage') %></th>
14
- <td><%= @failure['error_message'] %></td>
15
- </tr>
16
- <% if !@failure['error_backtrace'].nil? %>
17
- <tr>
18
- <th><%= t('ErrorBacktrace') %></th>
19
- <td>
20
- <code><%= @failure['error_backtrace'].join("<br/>") %></code>
21
- </td>
22
- </tr>
23
- <% end %>
24
- </tbody>
25
- </table>
26
- <form class="form-horizontal" action="<%= root_path %>failures/<%= job_params(@failure, @failure.score) %>" method="post">
27
- <%= csrf_tag if respond_to?(:csrf_tag) %>
28
- <a class="btn" href="<%= root_path %>failures"><%= t('GoBack') %></a>
29
- <input class="btn btn-primary" type="submit" name="retry" value="<%= t('RetryNow') %>" />
30
- <input class="btn btn-danger" type="submit" name="delete" value="<%= t('Delete') %>" />
31
- </form>
3
+ <section>
4
+ <header>
5
+ <h2><%= t('Error') %></h2>
6
+ </header>
7
+
8
+ <div class="table_container">
9
+ <table>
10
+ <tbody>
11
+ <tr>
12
+ <th><%= t('ErrorClass') %></th>
13
+ <td>
14
+ <code><%= h @failure['error_class'] %></code>
15
+ </td>
16
+ </tr>
17
+ <tr>
18
+ <th><%= t('ErrorMessage') %></th>
19
+ <td><%= h @failure['error_message'] %></td>
20
+ </tr>
21
+ <% if !@failure['error_backtrace'].nil? %>
22
+ <tr>
23
+ <th><%= t('ErrorBacktrace') %></th>
24
+ <td>
25
+ <code><%= @failure['error_backtrace'].join("<br/>") %></code>
26
+ </td>
27
+ </tr>
28
+ <% end %>
29
+ </tbody>
30
+ </table>
31
+ </div>
32
+
33
+ <form action="<%= root_path %>failures/<%= job_params(@failure, @failure.score) %>" method="post">
34
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
35
+ <a class="btn btn-default" href="<%= root_path %>failures"><%= t('GoBack') %></a>
36
+ <input class="btn btn-primary" type="submit" name="retry" value="<%= t('RetryNow') %>" />
37
+ <input class="btn btn-danger" type="submit" name="delete" value="<%= t('Delete') %>" />
38
+ </form>
39
+ </section>
@@ -0,0 +1,31 @@
1
+ <%= erb :_job_info, :locals => {:job => @failure, :type => :failure} %>
2
+
3
+ <h3><%= t('Error') %></h3>
4
+ <table class="error table table-bordered table-striped">
5
+ <tbody>
6
+ <tr>
7
+ <th><%= t('ErrorClass') %></th>
8
+ <td>
9
+ <code><%= h @failure['error_class'] %></code>
10
+ </td>
11
+ </tr>
12
+ <tr>
13
+ <th><%= t('ErrorMessage') %></th>
14
+ <td><%= h @failure['error_message'] %></td>
15
+ </tr>
16
+ <% if !@failure['error_backtrace'].nil? %>
17
+ <tr>
18
+ <th><%= t('ErrorBacktrace') %></th>
19
+ <td>
20
+ <code><%= @failure['error_backtrace'].join("<br/>") %></code>
21
+ </td>
22
+ </tr>
23
+ <% end %>
24
+ </tbody>
25
+ </table>
26
+ <form class="form-horizontal" action="<%= root_path %>failures/<%= job_params(@failure, @failure.score) %>" method="post">
27
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
28
+ <a class="btn" href="<%= root_path %>failures"><%= t('GoBack') %></a>
29
+ <input class="btn btn-primary" type="submit" name="retry" value="<%= t('RetryNow') %>" />
30
+ <input class="btn btn-danger" type="submit" name="delete" value="<%= t('Delete') %>" />
31
+ </form>
@@ -1,85 +1,113 @@
1
- <header class="row">
2
- <div class="col-sm-5">
3
- <h3><%= t('FailedJobs') %></h3>
4
- </div>
5
- <% if @failures.size > 0 && @total_size > @count %>
6
- <div class="col-sm-4">
1
+ <section>
2
+ <header>
3
+ <h1>
4
+ <span class="title"><%= t('FailedJobs') %></span>
5
+ <span class="badge badge-secondary"><%= number_with_delimiter(@failures.count) %></span>
6
+ </h1>
7
+ <% if @failures.count > 0 && @total_size > @count %>
7
8
  <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
8
- </div>
9
- <% end %>
10
- <%= filtering('failures') if respond_to?(:filtering) %>
11
- </header>
9
+ <% end %>
10
+ <%= filtering('failures') if respond_to?(:filtering) %>
11
+ </header>
12
12
 
13
- <% if @failures.size > 0 %>
14
- <form action="<%= root_path %>failures" method="post">
15
- <%= csrf_tag if respond_to?(:csrf_tag) %>
16
- <table class="table table-striped table-bordered table-white">
17
- <thead>
18
- <tr>
19
- <th width="20px" class="table-checkbox">
20
- <label>
21
- <input type="checkbox" class="check_all" />
22
- </label>
23
- </th>
24
- <th style="width: 20%"><%= t('Worker') %></th>
25
- <th style="width: 10%"><%= t('Arguments') %></th>
26
- <th style="width: 10%"><%= t('Queue') %></th>
27
- <th style="width: 10%"><%= t('FailedAt') %></th>
28
- <th style="width: 50%"><%= t('Error') %></th>
29
- </tr>
30
- </thead>
31
- <% @failures.each do |entry| %>
32
- <tr>
33
- <td class="table-checkbox">
34
- <label>
35
- <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
36
- </label>
37
- </td>
38
- <td><a href="<%= root_path %>failures/<%= job_params(entry.item, entry.score) %>"><%= entry.klass %></a></td>
39
- <td>
40
- <div class="args"><%= display_args(entry.args) %></div>
41
- </td>
42
- <td>
43
- <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
44
- </td>
45
- <td><%= safe_relative_time(entry['failed_at']) %></td>
46
- <td style="overflow: auto; padding: 10px;">
47
- <a class="backtrace" href="#" onclick="$(this).next().toggle(); return false">
48
- <%= h entry['error_class'] %>: <%= h entry['error_message'].size > 500 ? entry['error_message'][0..500] + '...' : entry['error_message'] %>
49
- </a>
50
- <pre style="display: none; background: none; border: 0; width: 100%; max-height: 30em; font-size: 0.8em; white-space: nowrap; overflow: auto;">
51
- <%= entry['error_backtrace'].join("<br />") if entry['error_backtrace'] %>
52
- </pre>
53
- <p>
54
- <span>Processor: <%= entry['processor'] %></span>
55
- </p>
56
- </td>
57
- </tr>
58
- <% end %>
59
- </table>
60
- <input class="btn btn-primary btn-xs pull-left" type="submit" name="retry" value="<%= t('RetryNow') %>" />
61
- <input class="btn btn-danger btn-xs pull-left" type="submit" name="delete" value="<%= t('Delete') %>" />
62
- </form>
13
+ <% if @failures.count > 0 %>
14
+ <form action="<%= root_path %>failures" method="post">
15
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
16
+ <div class="table_container">
17
+ <table>
18
+ <thead>
19
+ <tr>
20
+ <th width="20px" class="table-checkbox">
21
+ <label>
22
+ <input type="checkbox" class="check_all" />
23
+ </label>
24
+ </th>
25
+ <th><%= t('FailedAt') %></th>
26
+ <th><%= t('Queue') %></th>
27
+ <th><%= t('Worker') %></th>
28
+ <th><%= t('Arguments') %></th>
29
+ <th><%= t('Error') %></th>
30
+ </tr>
31
+ </thead>
32
+ <% @failures.each do |entry| %>
33
+ <tr>
34
+ <td class="table-checkbox">
35
+ <label>
36
+ <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
37
+ </label>
38
+ </td>
39
+ <td>
40
+ <a href="<%= root_path %>failures/<%= job_params(entry.item, entry.score) %>"><%= safe_relative_time(entry['failed_at']) %></a>
41
+ </td>
42
+ <td>
43
+ <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
44
+ </td>
45
+ <td><%= entry.respond_to?(:display_class) ? entry.display_class : entry.klass %></td>
46
+ <td>
47
+ <code>
48
+ <div class="args"><%= display_args(entry.respond_to?(:display_args) ? entry.display_args : entry.args) %></div>
49
+ </code>
50
+ </td>
51
+ <td>
52
+ <% error_class = entry['error_class'].to_s %>
53
+ <% error_message = entry['error_message'].to_s %>
54
+ <% error_text = "#{h(error_class)}: #{h(error_message)}" %>
55
+ <% truncated_error = truncate(error_text, 200) %>
63
56
 
64
- <form action="<%= root_path %>failures/all/delete" method="post">
65
- <%= csrf_tag if respond_to?(:csrf_tag) %>
66
- <input class="btn btn-danger btn-xs pull-right" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
67
- </form>
68
- <form action="<%= root_path %>failures/all/retry" method="post">
69
- <%= csrf_tag if respond_to?(:csrf_tag) %>
70
- <input class="btn btn-danger btn-xs pull-right" type="submit" name="retry" value="<%= t('RetryAll') %>" data-confirm="<%= t('AreYouSure') %>" />
71
- </form>
57
+ <% if entry['error_backtrace'] %>
58
+ <details>
59
+ <summary>
60
+ <%= truncated_error %>
61
+ </summary>
62
+ <% if entry['error_backtrace'] %>
63
+ <code>
64
+ <%= entry['error_backtrace'].join("<br/>") %>
65
+ </code>
66
+ <% end %>
67
+ </details>
68
+ <% else %>
69
+ <div>
70
+ <%= truncated_error %>
71
+ </div>
72
+ <% end %>
73
+ <div>
74
+ <span>Processor: <%= entry['processor'] %></span>
75
+ </div>
76
+ </td>
77
+ </tr>
78
+ <% end %>
79
+ </table>
80
+ </div>
81
+ <div class="buttons-row">
82
+ <input class="btn btn-primary btn-xs pull-left" type="submit" name="retry" value="<%= t('RetryNow') %>" />
83
+ <input class="btn btn-danger btn-xs pull-left" type="submit" name="delete" value="<%= t('Delete') %>" />
84
+ </div>
85
+ </form>
72
86
 
73
- <% if @failures.size > 0 && @total_size > @count %>
74
- <div class="col-sm-4">
75
- <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
87
+ <div class="buttons-row">
88
+ <form action="<%= root_path %>failures/all/delete" method="post">
89
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
90
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
91
+ </form>
92
+ <form action="<%= root_path %>failures/all/retry" method="post">
93
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
94
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="retry" value="<%= t('RetryAll') %>" data-confirm="<%= t('AreYouSure') %>" />
95
+ </form>
76
96
  </div>
97
+
98
+ <% if @failures.count > 0 && @total_size > @count %>
99
+ <div>
100
+ <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
101
+ </div>
102
+ <% end %>
103
+ <% else %>
104
+ <div class="alert alert-success"><%= t('NoFailedJobsFound') %></div>
77
105
  <% end %>
78
106
 
79
- <% else %>
80
- <div class="alert alert-success"><%= t('NoFailedJobsFound') %></div>
81
- <% end %>
82
- <form action="<%= root_path %>failures/all/reset" method="post">
83
- <%= csrf_tag if respond_to?(:csrf_tag) %>
84
- <input class="btn btn-danger btn-xs pull-right" type="submit" name="reset" value="<%= t('Reset Counter') %>" data-confirm="<%= t('AreYouSure') %>" />
85
- </form>
107
+ <div class="buttons-row">
108
+ <form action="<%= root_path %>failures/all/reset" method="post">
109
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
110
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="reset" value="<%= t('ResetCounter') %>" data-confirm="<%= t('AreYouSure') %>" />
111
+ </form>
112
+ </div>
113
+ </section>
@@ -0,0 +1,105 @@
1
+ <header class="row">
2
+ <div class="col-sm-5">
3
+ <h3><%= t('FailedJobs') %></h3>
4
+ </div>
5
+ <% if @failures.count > 0 && @total_size > @count %>
6
+ <div class="col-sm-4">
7
+ <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
8
+ </div>
9
+ <% end %>
10
+ <%= filtering('failures') if respond_to?(:filtering) %>
11
+ </header>
12
+
13
+ <% if @failures.count > 0 %>
14
+ <form action="<%= root_path %>failures" method="post">
15
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
16
+ <table class="table table-striped table-bordered table-white">
17
+ <thead>
18
+ <tr>
19
+ <th width="20px" class="table-checkbox">
20
+ <label>
21
+ <input type="checkbox" class="check_all" />
22
+ </label>
23
+ </th>
24
+ <th><%= t('FailedAt') %></th>
25
+ <th><%= t('Queue') %></th>
26
+ <th><%= t('Worker') %></th>
27
+ <th><%= t('Arguments') %></th>
28
+ <th><%= t('Error') %></th>
29
+ </tr>
30
+ </thead>
31
+ <% @failures.each do |entry| %>
32
+ <tr>
33
+ <td class="table-checkbox">
34
+ <label>
35
+ <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
36
+ </label>
37
+ </td>
38
+ <td>
39
+ <a href="<%= root_path %>failures/<%= job_params(entry.item, entry.score) %>"><%= safe_relative_time(entry['failed_at']) %></a>
40
+ </td>
41
+ <td>
42
+ <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
43
+ </td>
44
+ <td><%= entry.respond_to?(:display_class) ? entry.display_class : entry.klass %></td>
45
+ <td>
46
+ <div class="args"><%= display_args(entry.respond_to?(:display_args) ? entry.display_args : entry.args) %></div>
47
+ </td>
48
+ <td style="overflow: auto; padding: 10px;">
49
+ <a class="backtrace" href="javascript:void(0)", onclick="toggle_error_backtrace(this)">
50
+ <%= h entry['error_class'] %>: <%= h entry['error_message'].to_s.size > 500 ? entry['error_message'][0..500] + '...' : entry['error_message'] %>
51
+ </a>
52
+ <pre style="display: none; background: none; border: 0; width: 100%; max-height: 30em; font-size: 0.8em; white-space: nowrap; overflow: auto;">
53
+ <%= entry['error_backtrace'].join("<br />") if entry['error_backtrace'] %>
54
+ </pre>
55
+ <p>
56
+ <span>Processor: <%= entry['processor'] %></span>
57
+ </p>
58
+ </td>
59
+ </tr>
60
+ <% end %>
61
+ </table>
62
+ <input class="btn btn-primary btn-xs pull-left" type="submit" name="retry" value="<%= t('RetryNow') %>" />
63
+ <input class="btn btn-danger btn-xs pull-left" type="submit" name="delete" value="<%= t('Delete') %>" />
64
+ </form>
65
+
66
+ <form action="<%= root_path %>failures/all/delete" method="post">
67
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
68
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="delete" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
69
+ </form>
70
+ <form action="<%= root_path %>failures/all/retry" method="post">
71
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
72
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="retry" value="<%= t('RetryAll') %>" data-confirm="<%= t('AreYouSure') %>" />
73
+ </form>
74
+
75
+ <% if @failures.count > 0 && @total_size > @count %>
76
+ <div class="col-sm-4">
77
+ <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
78
+ </div>
79
+ <% end %>
80
+
81
+ <script>
82
+ function toggle_error_backtrace(e) {
83
+ let x = e.nextElementSibling;
84
+ if (x.style.display === "none") {
85
+ x.style.display = "block";
86
+ } else {
87
+ x.style.display = "none";
88
+ }
89
+ }
90
+ </script>
91
+
92
+ <style type="text/css">
93
+ @media only screen and (prefers-color-scheme: dark) {
94
+ pre {
95
+ color: white
96
+ }
97
+ }
98
+ </style>
99
+ <% else %>
100
+ <div class="alert alert-success"><%= t('NoFailedJobsFound') %></div>
101
+ <% end %>
102
+ <form action="<%= root_path %>failures/all/reset" method="post">
103
+ <%= csrf_tag if respond_to?(:csrf_tag) %>
104
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="reset" value="<%= t('ResetCounter') %>" data-confirm="<%= t('AreYouSure') %>" />
105
+ </form>