sidekiq-failures 0.4.5 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: 71e370c4485d8ecc481914afd5d8a489c9f2743c1749975dceb536977607230a
4
+ data.tar.gz: 1a8e989912c378459e478eb9f29c0dd1d53128c126cc135c2bf597375e26ed84
5
5
  SHA512:
6
- metadata.gz: dd021e8afcbd6a59c8d725d2954f7d45cbb50475b3c342b8e5d00533dd3c72594548d4fdb197e3d5a3cd51d158f000c050da57d353ef294c67bfe7880243dad8
7
- data.tar.gz: 422b175ead022b822ae08838a03365f22e6e4a0a2213ff8f9c2756ed3f41b14c58e9e7f950f32adce8d8f25e440c3a5a8b78753798a4162ddf8626cd9bb2c977
6
+ metadata.gz: 49f99dbee68555a41e53d615e27afa48f5852d0f887fd96891864c89fd86f5d72fe552d9eefa5b22f860502d6bed321c38f5a4fd28ea5c4f1dfeea703c9d17eb
7
+ data.tar.gz: f59b94960937b9f7d3482c79f79b905015fac87df83bcde5db946023383658138d7226003431a4ece758780f0ad06e7a1b2785258917d19fc5a9278fe6583267
@@ -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]
16
+ sidekiq: [4.2, 5.2, 6.2]
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@v3
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/.gitignore CHANGED
@@ -17,4 +17,4 @@ tmp
17
17
  Gemfile.lock
18
18
  .ruby-version
19
19
  .ruby-gemset
20
-
20
+ .tool-versions
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 1.0.4
4
+
5
+ * Sanitize failure text on the failure details page (#144 @mcasper)
6
+
7
+ ## 1.0.3
8
+
9
+ * Expand failure descriptions with pure JS (#141 @icyleaf)
10
+
11
+ ## 1.0.2
12
+
13
+ * Pass now required argument to Sidekiq's JobRetry.new (#140 @mcasper)
14
+
15
+ ## 1.0.1
16
+
17
+ * Add license config to the gemspec (#115 @reiz)
18
+ * Guard against failure error_message being `nil` (#122 @mcasper)
19
+ * Fix filtering failures with 0 results on Sidekiq Pro (#125 @substars)
20
+
21
+ ## 1.0.0
22
+
23
+ * WebUI improvements (@bbtfr)
24
+ * Use ActiveJob to display info when available (@dreyks)
25
+ * New locales (@ryohashimoto @gurgelrenan)
26
+ * Sidekiq 4 and higher compatibility (@davekrupinski )
27
+ * Sidekiq 5 fixes (@fidelisrafael)
28
+
3
29
  ## 0.4.5
4
30
 
5
31
  * Limit error message to 500 symbols (@antonzaytsev)
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
@@ -136,7 +138,7 @@ Sidekiq::Failures.reset_failures
136
138
 
137
139
  ## Dependencies
138
140
 
139
- Depends on Sidekiq >= 2.16.0
141
+ Depends on Sidekiq >= 4.0.0
140
142
 
141
143
  ## Contributing
142
144
 
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Failures
3
- VERSION = "0.4.5"
3
+ VERSION = "1.0.4"
4
4
  end
5
5
  end
@@ -6,12 +6,12 @@
6
6
  <tr>
7
7
  <th><%= t('ErrorClass') %></th>
8
8
  <td>
9
- <code><%= @failure['error_class'] %></code>
9
+ <code><%= h @failure['error_class'] %></code>
10
10
  </td>
11
11
  </tr>
12
12
  <tr>
13
13
  <th><%= t('ErrorMessage') %></th>
14
- <td><%= @failure['error_message'] %></td>
14
+ <td><%= h @failure['error_message'] %></td>
15
15
  </tr>
16
16
  <% if !@failure['error_backtrace'].nil? %>
17
17
  <tr>
@@ -2,7 +2,7 @@
2
2
  <div class="col-sm-5">
3
3
  <h3><%= t('FailedJobs') %></h3>
4
4
  </div>
5
- <% if @failures.size > 0 && @total_size > @count %>
5
+ <% if @failures.count > 0 && @total_size > @count %>
6
6
  <div class="col-sm-4">
7
7
  <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
8
8
  </div>
@@ -10,7 +10,7 @@
10
10
  <%= filtering('failures') if respond_to?(:filtering) %>
11
11
  </header>
12
12
 
13
- <% if @failures.size > 0 %>
13
+ <% if @failures.count > 0 %>
14
14
  <form action="<%= root_path %>failures" method="post">
15
15
  <%= csrf_tag if respond_to?(:csrf_tag) %>
16
16
  <table class="table table-striped table-bordered table-white">
@@ -21,11 +21,11 @@
21
21
  <input type="checkbox" class="check_all" />
22
22
  </label>
23
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>
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
29
  </tr>
30
30
  </thead>
31
31
  <% @failures.each do |entry| %>
@@ -35,17 +35,19 @@
35
35
  <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
36
36
  </label>
37
37
  </td>
38
- <td><a href="<%= root_path %>failures/<%= job_params(entry.item, entry.score) %>"><%= entry.klass %></a></td>
39
38
  <td>
40
- <div class="args"><%= display_args(entry.args) %></div>
39
+ <a href="<%= root_path %>failures/<%= job_params(entry.item, entry.score) %>"><%= safe_relative_time(entry['failed_at']) %></a>
41
40
  </td>
42
41
  <td>
43
42
  <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
44
43
  </td>
45
- <td><%= safe_relative_time(entry['failed_at']) %></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>
46
48
  <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 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'] %>
49
51
  </a>
50
52
  <pre style="display: none; background: none; border: 0; width: 100%; max-height: 30em; font-size: 0.8em; white-space: nowrap; overflow: auto;">
51
53
  <%= entry['error_backtrace'].join("<br />") if entry['error_backtrace'] %>
@@ -70,16 +72,34 @@
70
72
  <input class="btn btn-danger btn-xs pull-right" type="submit" name="retry" value="<%= t('RetryAll') %>" data-confirm="<%= t('AreYouSure') %>" />
71
73
  </form>
72
74
 
73
- <% if @failures.size > 0 && @total_size > @count %>
75
+ <% if @failures.count > 0 && @total_size > @count %>
74
76
  <div class="col-sm-4">
75
77
  <%= erb :_paging, :locals => { :url => "#{root_path}failures" } %>
76
78
  </div>
77
79
  <% end %>
78
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>
79
99
  <% else %>
80
100
  <div class="alert alert-success"><%= t('NoFailedJobsFound') %></div>
81
101
  <% end %>
82
102
  <form action="<%= root_path %>failures/all/reset" method="post">
83
103
  <%= 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') %>" />
104
+ <input class="btn btn-danger btn-xs pull-right" type="submit" name="reset" value="<%= t('ResetCounter') %>" data-confirm="<%= t('AreYouSure') %>" />
85
105
  </form>
@@ -19,7 +19,7 @@ module Sidekiq
19
19
 
20
20
  app.get "/failures" do
21
21
  @count = (params[:count] || 25).to_i
22
- (@current_page, @total_size, @failures) = page(LIST_KEY, params[:page], @count)
22
+ (@current_page, @total_size, @failures) = page(LIST_KEY, params[:page], @count, :reverse => true)
23
23
  @failures = @failures.map {|msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
24
24
 
25
25
  render(:erb, File.read(File.join(view_path, "failures.erb")))
@@ -78,6 +78,17 @@ module Sidekiq
78
78
  FailureSet.new.retry_all_failures
79
79
  redirect "#{root_path}failures"
80
80
  end
81
+
82
+ app.get '/filter/failures' do
83
+ redirect "#{root_path}failures"
84
+ end
85
+
86
+ app.post '/filter/failures' do
87
+ @failures = Sidekiq::Failures::FailureSet.new.scan("*#{params[:substr]}*")
88
+ @current_page = 1
89
+ @count = @total_size = @failures.count
90
+ render(:erb, File.read(File.join(view_path, "failures.erb")))
91
+ end
81
92
  end
82
93
  end
83
94
  end
@@ -5,6 +5,7 @@ rescue LoadError
5
5
  end
6
6
 
7
7
  require "sidekiq/api"
8
+ require "sidekiq/version"
8
9
  require "sidekiq/failures/version"
9
10
  require "sidekiq/failures/sorted_entry"
10
11
  require "sidekiq/failures/failure_set"
@@ -47,9 +48,11 @@ module Sidekiq
47
48
 
48
49
  # Fetches the failures max count value
49
50
  def self.failures_max_count
50
- return 1000 if @failures_max_count.nil?
51
-
52
- @failures_max_count
51
+ if !instance_variable_defined?(:@failures_max_count) || @failures_max_count.nil?
52
+ 1000
53
+ else
54
+ @failures_max_count
55
+ end
53
56
  end
54
57
 
55
58
  module Failures
@@ -62,12 +65,23 @@ module Sidekiq
62
65
  def self.count
63
66
  Sidekiq.redis {|r| r.zcard(LIST_KEY) }
64
67
  end
68
+
69
+ def self.retry_middleware_class
70
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('5.0.0')
71
+ require 'sidekiq/job_retry'
72
+ Sidekiq::JobRetry
73
+ else
74
+ require 'sidekiq/middleware/server/retry_jobs'
75
+ Sidekiq::Middleware::Server::RetryJobs
76
+ end
77
+ end
78
+
65
79
  end
66
80
  end
67
81
 
68
82
  Sidekiq.configure_server do |config|
69
83
  config.server_middleware do |chain|
70
- chain.insert_before Sidekiq::Middleware::Server::RetryJobs,
84
+ chain.insert_before Sidekiq::Failures.retry_middleware_class,
71
85
  Sidekiq::Failures::Middleware
72
86
  end
73
87
  end
@@ -7,18 +7,26 @@ Gem::Specification.new do |gem|
7
7
  gem.description = %q{Keep track of Sidekiq failed jobs}
8
8
  gem.summary = %q{Keeps track of Sidekiq failed jobs and adds a tab to the Web UI to let you browse them. Makes use of Sidekiq's custom tabs and middleware chain.}
9
9
  gem.homepage = "https://github.com/mhfs/sidekiq-failures/"
10
+ gem.license = "MIT"
10
11
 
11
12
  gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
13
  gem.name = "sidekiq-failures"
15
14
  gem.require_paths = ["lib"]
16
15
  gem.version = Sidekiq::Failures::VERSION
17
16
 
18
- gem.add_dependency "sidekiq", ">= 2.16.0"
17
+ gem.add_dependency "sidekiq", ">= 4.0.0"
19
18
 
19
+ # Redis 4.X is incompatible with Ruby < 2.3, but the Ruby version constraint
20
+ # wasn't added until 4.1.2, meaning you can get an incompatible version of the
21
+ # redis gem when running Ruby 2.2 without this constraint.
22
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.3.0")
23
+ gem.add_dependency "redis", "< 4.0"
24
+ end
25
+
26
+ gem.add_development_dependency "minitest"
20
27
  gem.add_development_dependency "rake"
21
28
  gem.add_development_dependency "rack-test"
22
29
  gem.add_development_dependency "sprockets"
23
30
  gem.add_development_dependency "sinatra"
31
+ gem.add_development_dependency "pry"
24
32
  end
@@ -0,0 +1,16 @@
1
+ require "test_helper"
2
+
3
+ module Sidekiq
4
+ describe Failures do
5
+ describe '.retry_middleware_class' do
6
+ it 'returns based on Sidekiq::VERISON' do
7
+ case Sidekiq::VERSION[0]
8
+ when '5'
9
+ assert_equal Failures.retry_middleware_class, Sidekiq::JobRetry
10
+ when '4'
11
+ assert_equal Failures.retry_middleware_class, Sidekiq::Middleware::Server::RetryJobs
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,19 +1,72 @@
1
1
  require "test_helper"
2
2
 
3
+ class SidekiqPre6
4
+ def new_processor(boss)
5
+ num_options_calls.times { boss.expect(:options, {:queues => ['default'] }, []) }
6
+ ::Sidekiq::Processor.new(boss)
7
+ end
8
+
9
+ private
10
+
11
+ def num_options_calls
12
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new('5.0.3')
13
+ 3
14
+ else
15
+ 2
16
+ end
17
+ end
18
+ end
19
+
20
+ class SidekiqPre63
21
+ def new_processor(boss)
22
+ opts = {
23
+ queues: ['default'],
24
+ }
25
+ opts[:fetch] = Sidekiq::BasicFetch.new(opts)
26
+ ::Sidekiq::Processor.new(boss, opts)
27
+ end
28
+ end
29
+
30
+ class SidekiqPost63
31
+ def new_processor(boss)
32
+ config = Sidekiq
33
+ config[:queues] = ['default']
34
+ config[:fetch] = Sidekiq::BasicFetch.new(config)
35
+ config[:error_handlers] << Sidekiq.method(:default_error_handler)
36
+ ::Sidekiq::Processor.new(config) { |processor, reason = nil| }
37
+ end
38
+ end
39
+
3
40
  module Sidekiq
4
41
  module Failures
5
42
  describe "Middleware" do
43
+ def new_provider
44
+ version = Gem::Version.new(Sidekiq::VERSION)
45
+ if version >= Gem::Version.new('6.4.0')
46
+ SidekiqPost63
47
+ elsif version >= Gem::Version.new('6.0')
48
+ SidekiqPre63
49
+ else
50
+ SidekiqPre6
51
+ end.new
52
+ end
53
+
6
54
  before do
7
- Celluloid.boot
8
55
  $invokes = 0
9
56
  @boss = MiniTest::Mock.new
10
- @processor = ::Sidekiq::Processor.new(@boss)
57
+ @provider = new_provider
58
+ @processor = @provider.new_processor(@boss)
59
+
11
60
  Sidekiq.server_middleware {|chain| chain.add Sidekiq::Failures::Middleware }
12
61
  Sidekiq.redis = REDIS
13
62
  Sidekiq.redis { |c| c.flushdb }
14
63
  Sidekiq.instance_eval { @failures_default_mode = nil }
15
64
  end
16
65
 
66
+ after do
67
+ @boss.verify
68
+ end
69
+
17
70
  TestException = Class.new(Exception)
18
71
  ShutdownException = Class.new(Sidekiq::Shutdown)
19
72
 
@@ -42,11 +95,6 @@ module Sidekiq
42
95
 
43
96
  assert_equal 0, failures_count
44
97
 
45
- actor = MiniTest::Mock.new
46
- actor.expect(:processor_done, nil, [@processor])
47
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
48
- 2.times { @boss.expect(:async, actor, []) }
49
-
50
98
  assert_raises TestException do
51
99
  @processor.process(msg)
52
100
  end
@@ -60,11 +108,6 @@ module Sidekiq
60
108
 
61
109
  assert_equal 0, failures_count
62
110
 
63
- actor = MiniTest::Mock.new
64
- actor.expect(:processor_done, nil, [@processor])
65
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
66
- 2.times { @boss.expect(:async, actor, []) }
67
-
68
111
  assert_raises TestException do
69
112
  @processor.process(msg)
70
113
  end
@@ -78,13 +121,7 @@ module Sidekiq
78
121
 
79
122
  assert_equal 0, failures_count
80
123
 
81
- actor = MiniTest::Mock.new
82
- actor.expect(:processor_done, nil, [@processor])
83
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
84
- 2.times { @boss.expect(:async, actor, []) }
85
-
86
124
  @processor.process(msg)
87
- @boss.verify
88
125
 
89
126
  assert_equal 0, failures_count
90
127
  assert_equal 1, $invokes
@@ -95,11 +132,6 @@ module Sidekiq
95
132
 
96
133
  assert_equal 0, failures_count
97
134
 
98
- actor = MiniTest::Mock.new
99
- actor.expect(:processor_done, nil, [@processor])
100
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
101
- 2.times { @boss.expect(:async, actor, []) }
102
-
103
135
  assert_raises TestException do
104
136
  @processor.process(msg)
105
137
  end
@@ -115,11 +147,6 @@ module Sidekiq
115
147
 
116
148
  assert_equal 0, failures_count
117
149
 
118
- actor = MiniTest::Mock.new
119
- actor.expect(:processor_done, nil, [@processor])
120
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
121
- 2.times { @boss.expect(:async, actor, []) }
122
-
123
150
  assert_raises TestException do
124
151
  @processor.process(msg)
125
152
  end
@@ -134,11 +161,6 @@ module Sidekiq
134
161
 
135
162
  assert_equal 0, failures_count
136
163
 
137
- actor = MiniTest::Mock.new
138
- actor.expect(:processor_done, nil, [@processor])
139
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
140
- 2.times { @boss.expect(:async, actor, []) }
141
-
142
164
  assert_raises TestException do
143
165
  @processor.process(msg)
144
166
  end
@@ -152,11 +174,6 @@ module Sidekiq
152
174
 
153
175
  assert_equal 0, failures_count
154
176
 
155
- actor = MiniTest::Mock.new
156
- actor.expect(:processor_done, nil, [@processor])
157
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
158
- 2.times { @boss.expect(:async, actor, []) }
159
-
160
177
  assert_raises TestException do
161
178
  @processor.process(msg)
162
179
  end
@@ -170,11 +187,6 @@ module Sidekiq
170
187
 
171
188
  assert_equal 0, failures_count
172
189
 
173
- actor = MiniTest::Mock.new
174
- actor.expect(:processor_done, nil, [@processor])
175
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
176
- 2.times { @boss.expect(:async, actor, []) }
177
-
178
190
  assert_raises TestException do
179
191
  @processor.process(msg)
180
192
  end
@@ -190,11 +202,6 @@ module Sidekiq
190
202
 
191
203
  assert_equal 0, failures_count
192
204
 
193
- actor = MiniTest::Mock.new
194
- actor.expect(:processor_done, nil, [@processor])
195
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
196
- 2.times { @boss.expect(:async, actor, []) }
197
-
198
205
  assert_raises TestException do
199
206
  @processor.process(msg)
200
207
  end
@@ -210,11 +217,6 @@ module Sidekiq
210
217
 
211
218
  assert_equal 0, failures_count
212
219
 
213
- actor = MiniTest::Mock.new
214
- actor.expect(:processor_done, nil, [@processor])
215
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
216
- 2.times { @boss.expect(:async, actor, []) }
217
-
218
220
  assert_raises TestException do
219
221
  @processor.process(msg)
220
222
  end
@@ -233,16 +235,13 @@ module Sidekiq
233
235
 
234
236
  3.times do
235
237
  boss = MiniTest::Mock.new
236
- processor = ::Sidekiq::Processor.new(boss)
237
-
238
- actor = MiniTest::Mock.new
239
- actor.expect(:processor_done, nil, [processor])
240
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
241
- 2.times { boss.expect(:async, actor, []) }
238
+ processor = @provider.new_processor(boss)
242
239
 
243
240
  assert_raises TestException do
244
241
  processor.process(msg)
245
242
  end
243
+
244
+ boss.verify
246
245
  end
247
246
 
248
247
  assert_equal 2, failures_count
@@ -259,11 +258,6 @@ module Sidekiq
259
258
 
260
259
  assert_equal 0, Sidekiq::Failures.count
261
260
 
262
- actor = MiniTest::Mock.new
263
- actor.expect(:processor_done, nil, [@processor])
264
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
265
- @boss.expect(:async, actor, [])
266
-
267
261
  assert_raises TestException do
268
262
  @processor.process(msg)
269
263
  end
data/test/test_helper.rb CHANGED
@@ -1,5 +1,4 @@
1
- Encoding.default_external = Encoding::UTF_8
2
- Encoding.default_internal = Encoding::UTF_8
1
+ $TESTING = true
3
2
 
4
3
  require "minitest/autorun"
5
4
  require "minitest/spec"
@@ -7,14 +6,13 @@ require "minitest/mock"
7
6
 
8
7
  require "rack/test"
9
8
 
10
- require "celluloid"
11
9
  require "sidekiq"
10
+ require "sidekiq-pro" if ENV['SIDEKIQ_PRO_VERSION']
12
11
  require "sidekiq-failures"
13
12
  require "sidekiq/processor"
14
13
  require "sidekiq/fetch"
15
14
  require "sidekiq/cli"
16
15
 
17
- Celluloid.logger = nil
18
16
  Sidekiq.logger.level = Logger::ERROR
19
17
 
20
- REDIS = Sidekiq::RedisConnection.create(:url => "redis://localhost/15", :namespace => 'sidekiq_failures_test')
18
+ REDIS = Sidekiq::RedisConnection.create(url: "redis://localhost/15")
@@ -5,11 +5,15 @@ module Sidekiq
5
5
  describe "WebExtension" do
6
6
  include Rack::Test::Methods
7
7
 
8
+ TOKEN = SecureRandom.base64(32).freeze
9
+
8
10
  def app
9
11
  Sidekiq::Web
10
12
  end
11
13
 
12
14
  before do
15
+ env 'rack.session', { csrf: TOKEN }
16
+ env 'HTTP_X_CSRF_TOKEN', TOKEN
13
17
  Sidekiq.redis = REDIS
14
18
  Sidekiq.redis {|c| c.flushdb }
15
19
  end
@@ -17,22 +21,22 @@ module Sidekiq
17
21
  it 'can display home with failures tab' do
18
22
  get '/'
19
23
 
20
- last_response.status.must_equal 200
21
- last_response.body.must_match /Sidekiq/
22
- last_response.body.must_match /Failures/
24
+ _(last_response.status).must_equal 200
25
+ _(last_response.body).must_match(/Sidekiq/)
26
+ _(last_response.body).must_match(/Failures/)
23
27
  end
24
28
 
25
29
  it 'can display failures page without any failures' do
26
30
  get '/failures'
27
- last_response.status.must_equal 200
28
- last_response.body.must_match /Failed Jobs/
29
- last_response.body.must_match /No failed jobs found/
31
+ _(last_response.status).must_equal 200
32
+ _(last_response.body).must_match(/Failed Jobs/)
33
+ _(last_response.body).must_match(/No failed jobs found/)
30
34
  end
31
35
 
32
36
  it 'has the reset counter form and action' do
33
37
  get '/failures'
34
- last_response.body.must_match /failures\/all\/reset/
35
- last_response.body.must_match /Reset Counter/
38
+ _(last_response.body).must_match(/failures\/all\/reset/)
39
+ _(last_response.body).must_match(/Reset Counter/)
36
40
  end
37
41
 
38
42
  describe 'when there are failures' do
@@ -42,97 +46,105 @@ module Sidekiq
42
46
  end
43
47
 
44
48
  it 'should be successful' do
45
- last_response.status.must_equal 200
49
+ _(last_response.status).must_equal 200
46
50
  end
47
51
 
48
52
  it 'can display failures page with failures listed' do
49
- last_response.body.must_match /Failed Jobs/
50
- last_response.body.must_match /HardWorker/
51
- last_response.body.must_match /ArgumentError/
52
- last_response.body.wont_match /No failed jobs found/
53
+ _(last_response.body).must_match(/Failed Jobs/)
54
+ _(last_response.body).must_match(/HardWorker/)
55
+ _(last_response.body).must_match(/ArgumentError/)
56
+ _(last_response.body).wont_match(/No failed jobs found/)
53
57
  end
54
58
 
55
59
  it 'can reset counter' do
56
60
  assert_equal failed_count, "1"
57
61
 
58
- last_response.body.must_match /HardWorker/
62
+ _(last_response.body).must_match(/HardWorker/)
59
63
 
60
64
  post '/failures/all/reset'
61
- last_response.status.must_equal 302
62
- last_response.location.must_match /failures$/
65
+ _(last_response.status).must_equal 302
66
+ _(last_response.location).must_match(/failures$/)
63
67
 
64
68
  get '/failures'
65
- last_response.status.must_equal 200
66
- last_response.body.must_match /HardWorker/
69
+ _(last_response.status).must_equal 200
70
+ _(last_response.body).must_match(/HardWorker/)
67
71
 
68
72
  assert_equal failed_count, "0"
69
73
  end
70
74
 
71
75
  it 'has the delete all form and action' do
72
- last_response.body.must_match /failures\/all\/delete/
73
- last_response.body.must_match /Delete All/
76
+ _(last_response.body).must_match(/failures\/all\/delete/)
77
+ _(last_response.body).must_match(/Delete All/)
74
78
  end
75
79
 
76
80
  it 'can delete all failures' do
77
81
  assert_equal failed_count, "1"
78
82
 
79
- last_response.body.must_match /HardWorker/
83
+ _(last_response.body).must_match(/HardWorker/)
80
84
 
81
85
  post '/failures/all/delete'
82
- last_response.status.must_equal 302
83
- last_response.location.must_match /failures$/
86
+ _(last_response.status).must_equal 302
87
+ _(last_response.location).must_match(/failures$/)
84
88
 
85
89
  get '/failures'
86
- last_response.status.must_equal 200
87
- last_response.body.must_match /No failed jobs found/
90
+ _(last_response.status).must_equal 200
91
+ _(last_response.body).must_match(/No failed jobs found/)
88
92
 
89
93
  assert_equal failed_count, "1"
90
94
  end
91
95
 
92
96
  it 'has the retry all form and action' do
93
- last_response.body.must_match /failures\/all\/retry/
94
- last_response.body.must_match /Retry All/
97
+ _(last_response.body).must_match(/failures\/all\/retry/)
98
+ _(last_response.body).must_match(/Retry All/)
95
99
  end
96
100
 
97
101
  it 'can retry all failures' do
98
102
  assert_equal failed_count, "1"
99
103
 
100
- last_response.body.must_match /HardWorker/
104
+ _(last_response.body).must_match(/HardWorker/)
101
105
  post '/failures/all/retry'
102
- last_response.status.must_equal 302
103
- last_response.location.must_match /failures/
106
+ _(last_response.status).must_equal 302
107
+ _(last_response.location).must_match(/failures/)
104
108
 
105
109
  get '/failures'
106
- last_response.status.must_equal 200
107
- last_response.body.must_match(/No failed jobs found/)
110
+ _(last_response.status).must_equal 200
111
+ _(last_response.body).must_match(/No failed jobs found/)
108
112
  end
109
113
 
110
114
  it 'can delete failure from the list' do
111
115
  assert_equal failed_count, "1"
112
116
 
113
- last_response.body.must_match /HardWorker/
117
+ _(last_response.body).must_match(/HardWorker/)
114
118
 
115
119
  post '/failures', { :key => [failure_score], :delete => 'Delete' }
116
- last_response.status.must_equal 302
117
- last_response.location.must_match /failures/
120
+ _(last_response.status).must_equal 302
121
+ _(last_response.location).must_match(/failures/)
118
122
 
119
123
  get '/failures'
120
- last_response.status.must_equal 200
121
- last_response.body.must_match /No failed jobs found/
124
+ _(last_response.status).must_equal 200
125
+ _(last_response.body).must_match(/No failed jobs found/)
122
126
  end
123
127
 
124
128
  it 'can retry failure from the list' do
125
129
  assert_equal failed_count, "1"
126
130
 
127
- last_response.body.must_match /HardWorker/
131
+ _(last_response.body).must_match(/HardWorker/)
128
132
 
129
133
  post '/failures', { :key => [failure_score], :retry => 'Retry Now' }
130
- last_response.status.must_equal 302
131
- last_response.location.must_match /failures/
134
+ _(last_response.status).must_equal 302
135
+ _(last_response.location).must_match(/failures/)
136
+
137
+ get '/failures'
138
+ _(last_response.status).must_equal 200
139
+ _(last_response.body).must_match(/No failed jobs found/)
140
+ end
141
+
142
+ it 'can handle failures with nil error_message' do
143
+ create_sample_failure(error_message: nil)
132
144
 
133
145
  get '/failures'
134
- last_response.status.must_equal 200
135
- last_response.body.must_match /No failed jobs found/
146
+
147
+ _(last_response.status).must_equal 200
136
148
  end
137
149
  end
138
150
 
@@ -143,54 +155,82 @@ module Sidekiq
143
155
  end
144
156
 
145
157
  it 'should be successful' do
146
- last_response.status.must_equal 200
158
+ _(last_response.status).must_equal 200
147
159
  end
148
160
 
149
161
  it 'can display failure page' do
150
- last_response.body.must_match /Job/
151
- last_response.body.must_match /HardWorker/
152
- last_response.body.must_match /ArgumentError/
153
- last_response.body.must_match /file1/
162
+ _(last_response.body).must_match(/Job/)
163
+ _(last_response.body).must_match(/HardWorker/)
164
+ _(last_response.body).must_match(/ArgumentError/)
165
+ _(last_response.body).must_match(/file1/)
154
166
  end
155
167
 
156
168
  it 'can delete failure' do
157
- last_response.body.must_match /HardWorker/
169
+ _(last_response.body).must_match(/HardWorker/)
158
170
 
159
171
  post "/failures/#{failure_score}", :delete => 'Delete'
160
- last_response.status.must_equal 302
161
- last_response.location.must_match /failures/
172
+ _(last_response.status).must_equal 302
173
+ _(last_response.location).must_match(/failures/)
162
174
 
163
175
  get "/failures/#{failure_score}"
164
- last_response.status.must_equal 302
165
- last_response.location.must_match /failures/
176
+ _(last_response.status).must_equal 302
177
+ _(last_response.location).must_match(/failures/)
166
178
  end
167
179
 
168
180
  it 'can retry failure' do
169
- last_response.body.must_match /HardWorker/
181
+ _(last_response.body).must_match(/HardWorker/)
170
182
 
171
183
  post "/failures/#{failure_score}", :retry => 'Retry Now'
172
- last_response.status.must_equal 302
173
- last_response.location.must_match /failures/
184
+ _(last_response.status).must_equal 302
185
+ _(last_response.location).must_match(/failures/)
174
186
 
175
187
  get "/failures/#{failure_score}"
176
- last_response.status.must_equal 302
177
- last_response.location.must_match /failures/
188
+ _(last_response.status).must_equal 302
189
+ _(last_response.location).must_match(/failures/)
190
+ end
191
+
192
+ if defined? Sidekiq::Pro
193
+ it 'can filter failure' do
194
+ create_sample_failure
195
+ post '/filter/failures', substr: 'new'
196
+
197
+ _(last_response.status).must_equal 200
198
+ end
178
199
  end
179
200
  end
180
201
 
181
202
  describe 'when there is specific failure' do
182
203
  describe 'with unescaped data' do
183
- before do
184
- create_sample_failure(args: ['<h1>omg</h1>'], error_message: '<p>wow</p>')
185
- get '/failures'
204
+ describe 'the index page' do
205
+ before do
206
+ create_sample_failure(args: ['<h1>omg</h1>'], error_message: '<p>wow</p>')
207
+ get '/failures'
208
+ end
209
+
210
+ it 'can escape arguments' do
211
+ _(last_response.body).must_match(/&quot;&lt;h1&gt;omg&lt;&#x2F;h1&gt;&quot;/)
212
+ end
213
+
214
+ it 'can escape error message' do
215
+ _(last_response.body).must_match(/ArgumentError: &lt;p&gt;wow&lt;&#x2F;p&gt;/)
216
+ end
186
217
  end
187
218
 
188
- it 'can escape arguments' do
189
- last_response.body.must_match /&quot;&lt;h1&gt;omg&lt;&#x2F;h1&gt;&quot;/
190
- end
191
-
192
- it 'can escape error message' do
193
- last_response.body.must_match /ArgumentError: &lt;p&gt;wow&lt;&#x2F;p&gt;/
219
+ describe 'the details page' do
220
+ before do
221
+ failure = create_sample_failure(args: ['<h1>omg</h1>'], error_message: '<p>wow</p>')
222
+ get "/failures/#{failure[:jid]}"
223
+ end
224
+
225
+ it 'can escape arguments' do
226
+ _(last_response.status).must_equal 200
227
+ _(last_response.body).must_match(/<th>Error Message<\/th>\n <td>&lt;p&gt;wow&lt;&#x2F;p&gt;<\/td>/)
228
+ end
229
+
230
+ it 'can escape error message' do
231
+ _(last_response.status).must_equal 200
232
+ _(last_response.body).must_match(/<th>Error Message<\/th>\n <td>&lt;p&gt;wow&lt;&#x2F;p&gt;<\/td>/)
233
+ end
194
234
  end
195
235
  end
196
236
 
@@ -201,8 +241,8 @@ module Sidekiq
201
241
  end
202
242
 
203
243
  it 'should be successful' do
204
- last_response.status.must_equal 200
205
- last_response.body.wont_match /No failed jobs found/
244
+ _(last_response.status).must_equal 200
245
+ _(last_response.body).wont_match(/No failed jobs found/)
206
246
  end
207
247
  end
208
248
 
@@ -213,8 +253,8 @@ module Sidekiq
213
253
  end
214
254
 
215
255
  it 'should be successful' do
216
- last_response.status.must_equal 200
217
- last_response.body.wont_match /No failed jobs found/
256
+ _(last_response.status).must_equal 200
257
+ _(last_response.body).wont_match(/No failed jobs found/)
218
258
  end
219
259
  end
220
260
  end
@@ -238,6 +278,8 @@ module Sidekiq
238
278
  c.set("stat:failed", 1)
239
279
  end
240
280
  end
281
+
282
+ data
241
283
  end
242
284
 
243
285
  def failed_count
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-failures
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcelo Silveira
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-21 00:00:00.000000000 Z
11
+ date: 2022-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.16.0
19
+ version: 4.0.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: 2.16.0
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  description: Keep track of Sidekiq failed jobs
84
112
  email:
85
113
  - marcelo@mhfs.com.br
@@ -87,8 +115,9 @@ executables: []
87
115
  extensions: []
88
116
  extra_rdoc_files: []
89
117
  files:
118
+ - ".github/dependabot.yml"
119
+ - ".github/workflows/ci.yml"
90
120
  - ".gitignore"
91
- - ".travis.yml"
92
121
  - CHANGELOG.md
93
122
  - Gemfile
94
123
  - LICENSE
@@ -98,6 +127,9 @@ files:
98
127
  - lib/sidekiq/failures.rb
99
128
  - lib/sidekiq/failures/failure_set.rb
100
129
  - lib/sidekiq/failures/locales/en.yml
130
+ - lib/sidekiq/failures/locales/ja.yml
131
+ - lib/sidekiq/failures/locales/pt-BR.yml
132
+ - lib/sidekiq/failures/locales/zh-cn.yml
101
133
  - lib/sidekiq/failures/middleware.rb
102
134
  - lib/sidekiq/failures/sorted_entry.rb
103
135
  - lib/sidekiq/failures/version.rb
@@ -105,13 +137,15 @@ files:
105
137
  - lib/sidekiq/failures/views/failures.erb
106
138
  - lib/sidekiq/failures/web_extension.rb
107
139
  - sidekiq-failures.gemspec
140
+ - test/failures_test.rb
108
141
  - test/middleware_test.rb
109
142
  - test/test_helper.rb
110
143
  - test/web_extension_test.rb
111
144
  homepage: https://github.com/mhfs/sidekiq-failures/
112
- licenses: []
145
+ licenses:
146
+ - MIT
113
147
  metadata: {}
114
- post_install_message:
148
+ post_install_message:
115
149
  rdoc_options: []
116
150
  require_paths:
117
151
  - lib
@@ -126,13 +160,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
160
  - !ruby/object:Gem::Version
127
161
  version: '0'
128
162
  requirements: []
129
- rubyforge_project:
130
- rubygems_version: 2.4.5
131
- signing_key:
163
+ rubygems_version: 3.0.3.1
164
+ signing_key:
132
165
  specification_version: 4
133
166
  summary: Keeps track of Sidekiq failed jobs and adds a tab to the Web UI to let you
134
167
  browse them. Makes use of Sidekiq's custom tabs and middleware chain.
135
- test_files:
136
- - test/middleware_test.rb
137
- - test/test_helper.rb
138
- - test/web_extension_test.rb
168
+ test_files: []
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- language: ruby
2
- services:
3
- - redis-server
4
- rvm:
5
- - 1.9.3
6
- - jruby-19mode
7
- - 2.0.0
8
- - 2.1
9
- env:
10
- matrix:
11
- - SIDEKIQ_VERSION="~> 2.16"
12
- - SIDEKIQ_VERSION="~> 2.17"
13
- - SIDEKIQ_VERSION="~> 3.0"
14
- - SIDEKIQ_VERSION="~> 3.1"
15
- matrix:
16
- allow_failures:
17
- - rvm: 1.9.3
18
- - rvm: jruby-19mode