sidekiq-expected_failures 0.0.1 → 0.2.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.
- data/.travis.yml +3 -0
- data/CHANGELOG.md +34 -0
- data/README.md +22 -2
- data/lib/sidekiq/expected_failures/middleware.rb +19 -7
- data/lib/sidekiq/expected_failures/version.rb +1 -1
- data/lib/sidekiq/expected_failures/web.rb +8 -20
- data/lib/sidekiq/expected_failures.rb +9 -0
- data/sidekiq-expected_failures.gemspec +2 -1
- data/test/lib/middleware_test.rb +66 -22
- data/test/lib/web_test.rb +5 -9
- data/test/test_helper.rb +6 -0
- data/test/test_workers.rb +11 -2
- data/web/assets/expected.js +1 -1
- data/web/views/expected_failures.erb +27 -10
- metadata +36 -20
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
## 0.2.0
|
2
|
+
|
3
|
+
- [**breaking change**] ability to use Sidekiq's build-in `handle_exception`
|
4
|
+
method - in case you want to use airbrake or other exception notify service.
|
5
|
+
Since version `0.2.0` you need to provide `expected_failures` in a form of
|
6
|
+
a hash, for example:
|
7
|
+
|
8
|
+
``` ruby
|
9
|
+
class CustomizedWorker
|
10
|
+
include ::Sidekiq::Worker
|
11
|
+
sidekiq_options expected_failures: {
|
12
|
+
NotImplementedError => nil, # notification disabled
|
13
|
+
VeryOwn::CustomException => [10, 20, 50], # notify on 10th, 20th, 50th failure
|
14
|
+
ZeroDivisionError => 5 # notify on 5th failure
|
15
|
+
}
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
- removed `sinatra-assetpack` dependency - js assets are now served inline
|
20
|
+
(it seemed like a overkill to include that gem just for just two files)
|
21
|
+
|
22
|
+
- added option to configure exception handled by default (for all workers):
|
23
|
+
|
24
|
+
``` ruby
|
25
|
+
Sidekiq.configure_server do |config|
|
26
|
+
config.expected_failures = { AlwaysHandledExceptionByDefault => 1000 }
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
Note: if you specify `expected_failure`s for given worker defaults will be
|
31
|
+
discarded (for that worker).
|
32
|
+
|
33
|
+
- small front-end adjustments
|
34
|
+
|
1
35
|
## 0.0.1
|
2
36
|
|
3
37
|
- Initial release
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://codeclimate.com/github/emq/sidekiq-expected_failures)
|
4
4
|
[](https://travis-ci.org/emq/sidekiq-expected_failures)
|
5
|
+
[](https://coveralls.io/r/emq/sidekiq-expected_failures)
|
5
6
|
|
6
7
|
If you don't rely on standard sidekiq's retry behavior and you want to track exceptions, that will happen one way, or another - this thing is for you.
|
7
8
|
|
@@ -26,7 +27,7 @@ Let's say you do a lot of API requests to some not reliable reliable service. In
|
|
26
27
|
``` ruby
|
27
28
|
class ApiCallWorker
|
28
29
|
include ::Sidekiq::Worker
|
29
|
-
sidekiq_options expected_failures:
|
30
|
+
sidekiq_options expected_failures: { Timeout::Error => nil } # handle that exception, but disable notification
|
30
31
|
|
31
32
|
def perform(arguments)
|
32
33
|
# do some work
|
@@ -42,12 +43,29 @@ class ApiCallWorker
|
|
42
43
|
end
|
43
44
|
```
|
44
45
|
|
45
|
-
You can pass
|
46
|
+
You can pass a hash of exceptions to handle inside `sidekiq_options`. Each key-value pair may consist of:
|
47
|
+
- `exception => nil` - notifications disabled
|
48
|
+
- `exception => integer` - fires exception notify when x-th exception happens (on daily basis)
|
49
|
+
- `exception => [integer, integer]` - same as above but for each value
|
50
|
+
|
51
|
+
sidekiq-expected_failures utilizes sidekiq's [ExceptionHandler module][1] - so you might want to set some same limits for your exceptions and use Airbrake (for example) as a notification service to inform you that something bad is probably happing.
|
52
|
+
|
53
|
+
This is how web interface looks like:
|
46
54
|
|
47
55
|

|
48
56
|
|
49
57
|
It logs each failed jobs to to redis list (per day) and keep global counters (per exception class as a single redis hash).
|
50
58
|
|
59
|
+
### Default expected failures
|
60
|
+
|
61
|
+
You can configure defaults for all your workers (overridden completely by specifying `expected_failures` hash inside `sidekiq_options` - per worker).
|
62
|
+
|
63
|
+
``` ruby
|
64
|
+
Sidekiq.configure_server do |config|
|
65
|
+
config.expected_failures = { ExceptionHandledByDefault => [1000, 2000] } # with notification enabled
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
51
69
|
### Usage with sidekiq-failures
|
52
70
|
|
53
71
|
Just be sure to load this one after `sidekiq-failures`, otherwise failed jobs will end up logged twice - and you probably don't want that.
|
@@ -69,3 +87,5 @@ This might change in the future to something more sane.
|
|
69
87
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
88
|
4. Push to the branch (`git push origin my-new-feature`)
|
71
89
|
5. Create new Pull Request
|
90
|
+
|
91
|
+
[1]: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/exception_handler.rb#L4
|
@@ -3,35 +3,47 @@ module Sidekiq
|
|
3
3
|
class Middleware
|
4
4
|
include Sidekiq::Util
|
5
5
|
|
6
|
+
attr_reader :handled_exceptions
|
7
|
+
|
6
8
|
def call(worker, msg, queue)
|
7
|
-
|
9
|
+
setup_exceptions(worker)
|
8
10
|
|
9
11
|
yield
|
10
12
|
|
11
|
-
rescue *
|
13
|
+
rescue *handled_exceptions.keys => ex
|
12
14
|
data = {
|
13
15
|
failed_at: Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
|
14
16
|
args: msg['args'],
|
15
|
-
exception:
|
16
|
-
error:
|
17
|
+
exception: ex.class.to_s,
|
18
|
+
error: ex.message,
|
17
19
|
worker: msg['class'],
|
18
20
|
processor: "#{hostname}:#{process_id}-#{Thread.current.object_id}",
|
19
21
|
queue: queue
|
20
22
|
}
|
21
23
|
|
22
|
-
log_exception(data)
|
24
|
+
log_exception(data, ex, msg)
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
26
28
|
|
27
|
-
def
|
28
|
-
|
29
|
+
def setup_exceptions(worker)
|
30
|
+
@handled_exceptions = worker.class.get_sidekiq_options['expected_failures'] || Sidekiq.expected_failures
|
31
|
+
end
|
32
|
+
|
33
|
+
def exception_intervals(ex)
|
34
|
+
[handled_exceptions[ex.class]].flatten.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_exception(data, ex, msg)
|
38
|
+
result = Sidekiq.redis do |conn|
|
29
39
|
conn.multi do |m|
|
30
40
|
m.lpush("expected:#{today}", Sidekiq.dump_json(data))
|
31
41
|
m.sadd("expected:dates", today)
|
32
42
|
m.hincrby("expected:count", data[:exception], 1)
|
33
43
|
end
|
34
44
|
end
|
45
|
+
|
46
|
+
handle_exception(ex, msg) if exception_intervals(ex).include?(result[0])
|
35
47
|
end
|
36
48
|
|
37
49
|
def today
|
@@ -1,20 +1,9 @@
|
|
1
|
-
require 'sinatra/assetpack'
|
2
|
-
|
3
1
|
module Sidekiq
|
4
2
|
module ExpectedFailures
|
5
3
|
module Web
|
6
4
|
|
7
5
|
def self.registered(app)
|
8
|
-
web_dir
|
9
|
-
assets_dir = File.join(web_dir, "assets")
|
10
|
-
|
11
|
-
app.register Sinatra::AssetPack
|
12
|
-
|
13
|
-
app.assets do
|
14
|
-
serve '/js', from: assets_dir
|
15
|
-
js 'expected', ['/js/expected.js']
|
16
|
-
js 'bootstrap', ['/js/bootstrap.js']
|
17
|
-
end
|
6
|
+
web_dir = File.expand_path("../../../../web", __FILE__)
|
18
7
|
|
19
8
|
app.helpers do
|
20
9
|
def link_to_details(job)
|
@@ -24,14 +13,9 @@ module Sidekiq
|
|
24
13
|
end
|
25
14
|
end
|
26
15
|
|
27
|
-
app.
|
28
|
-
|
29
|
-
|
30
|
-
Sidekiq::ExpectedFailures.clear_old
|
31
|
-
when 'all'
|
32
|
-
Sidekiq::ExpectedFailures.clear_all
|
33
|
-
when 'counters'
|
34
|
-
Sidekiq::ExpectedFailures.clear_counters
|
16
|
+
app.post "/expected_failures/clear" do
|
17
|
+
if %w(old all counters).include?(params[:what])
|
18
|
+
Sidekiq::ExpectedFailures.send("clear_#{params[:what]}")
|
35
19
|
end
|
36
20
|
|
37
21
|
redirect "#{root_path}expected_failures"
|
@@ -48,6 +32,10 @@ module Sidekiq
|
|
48
32
|
@counters = Sidekiq::ExpectedFailures.counters
|
49
33
|
end
|
50
34
|
|
35
|
+
@javascript = %w(expected bootstrap).map do |file|
|
36
|
+
File.read(File.join(web_dir, "assets/#{file}.js"))
|
37
|
+
end.join
|
38
|
+
|
51
39
|
erb File.read(File.join(web_dir, "views/expected_failures.erb"))
|
52
40
|
end
|
53
41
|
end
|
@@ -4,6 +4,15 @@ require "sidekiq/expected_failures/middleware"
|
|
4
4
|
require "sidekiq/expected_failures/web"
|
5
5
|
|
6
6
|
module Sidekiq
|
7
|
+
|
8
|
+
def self.expected_failures=(exceptions)
|
9
|
+
@expected_failures = exceptions
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.expected_failures
|
13
|
+
@expected_failures || {}
|
14
|
+
end
|
15
|
+
|
7
16
|
module ExpectedFailures
|
8
17
|
|
9
18
|
def self.dates
|
@@ -18,11 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_dependency "sidekiq", ">= 2.15.0"
|
21
|
-
spec.add_dependency "sinatra-assetpack", "~> 0.3.1"
|
22
21
|
|
23
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
23
|
spec.add_development_dependency "rake"
|
25
24
|
spec.add_development_dependency "sinatra"
|
26
25
|
spec.add_development_dependency "rack-test"
|
27
26
|
spec.add_development_dependency "timecop", "~> 0.6.3"
|
27
|
+
spec.add_development_dependency "mocha", "~> 0.14.0"
|
28
|
+
spec.add_development_dependency "coveralls", "~> 0.7.0"
|
28
29
|
end
|
data/test/lib/middleware_test.rb
CHANGED
@@ -8,6 +8,7 @@ module Sidekiq
|
|
8
8
|
Sidekiq.redis = REDIS
|
9
9
|
Sidekiq.redis { |c| c.flushdb }
|
10
10
|
Timecop.freeze(Time.local(2013, 1, 10))
|
11
|
+
Sidekiq.expected_failures = nil
|
11
12
|
end
|
12
13
|
|
13
14
|
after { Timecop.return }
|
@@ -23,44 +24,53 @@ module Sidekiq
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
it 'can can be configured to handle exceptions by default' do
|
28
|
+
Sidekiq.expected_failures = { VeryOwn::CustomException => nil }
|
29
|
+
|
30
|
+
handler.call(RegularWorker.new, msg, 'default') do
|
31
|
+
raise VeryOwn::CustomException
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_raises RuntimeError do
|
35
|
+
handler.call(RegularWorker.new, msg, 'default') do
|
36
|
+
raise "This is not handled by default"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
26
41
|
it 'respects build-in rescue and ensure blocks' do
|
27
42
|
assert_equal 0, $invokes
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
43
|
+
|
44
|
+
handler.call(SingleExceptionWorker.new, msg, 'default') do
|
45
|
+
begin
|
46
|
+
raise ZeroDivisionError.new("We go a problem, sir")
|
47
|
+
rescue ZeroDivisionError => e
|
48
|
+
$invokes += 1
|
49
|
+
raise e # and now this should be caught by middleware
|
50
|
+
ensure
|
51
|
+
$invokes += 1
|
38
52
|
end
|
39
53
|
end
|
54
|
+
|
40
55
|
assert_equal 2, $invokes
|
41
56
|
end
|
42
57
|
|
43
58
|
it 'handles all specified exceptions' do
|
44
|
-
|
45
|
-
|
46
|
-
raise NotImplementedError
|
47
|
-
end
|
59
|
+
handler.call(MultipleExceptionWorker.new, msg, 'default') do
|
60
|
+
raise NotImplementedError
|
48
61
|
end
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
raise VeryOwn::CustomException
|
53
|
-
end
|
63
|
+
handler.call(MultipleExceptionWorker.new, msg, 'default') do
|
64
|
+
raise VeryOwn::CustomException
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
57
68
|
it 'logs exceptions' do
|
58
|
-
|
59
|
-
|
60
|
-
raise ZeroDivisionError
|
61
|
-
end
|
69
|
+
handler.call(SingleExceptionWorker.new, msg, 'default') do
|
70
|
+
raise ZeroDivisionError
|
62
71
|
end
|
63
72
|
|
73
|
+
|
64
74
|
assert_equal(['2013-01-10'], redis("smembers", "expected:dates"))
|
65
75
|
assert_match(/custom_argument/, redis("lrange", "expected:2013-01-10", 0, -1)[0])
|
66
76
|
end
|
@@ -100,6 +110,40 @@ module Sidekiq
|
|
100
110
|
assert_equal 5, redis("llen", "expected:2013-05-15")
|
101
111
|
assert_equal(['2013-05-15', '2013-01-10'].sort, redis("smembers", "expected:dates").sort)
|
102
112
|
end
|
113
|
+
|
114
|
+
describe 'exception notify' do
|
115
|
+
|
116
|
+
it 'can be configured to notify once' do
|
117
|
+
exception = ZeroDivisionError.new
|
118
|
+
handler.expects(:handle_exception).with(exception, msg).once.returns(true)
|
119
|
+
|
120
|
+
50.times do
|
121
|
+
handler.call(CustomizedWorker.new, msg, 'default') do
|
122
|
+
raise exception
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'can be configured to notify multiple number of times' do
|
128
|
+
handler.expects(:handle_exception).times(3).returns(true)
|
129
|
+
|
130
|
+
60.times do
|
131
|
+
handler.call(CustomizedWorker.new, msg, 'default') do
|
132
|
+
raise VeryOwn::CustomException
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'can be configured not to notify at all' do
|
138
|
+
handler.expects(:handle_exception).never
|
139
|
+
|
140
|
+
60.times do
|
141
|
+
handler.call(CustomizedWorker.new, msg, 'default') do
|
142
|
+
raise NotImplementedError
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
103
147
|
end
|
104
148
|
end
|
105
149
|
end
|
data/test/lib/web_test.rb
CHANGED
@@ -9,10 +9,6 @@ module Sidekiq
|
|
9
9
|
Sidekiq::Web
|
10
10
|
end
|
11
11
|
|
12
|
-
def failed_count
|
13
|
-
Sidekiq.redis { |c| c.get("stat:failed") }
|
14
|
-
end
|
15
|
-
|
16
12
|
def create_sample_counter
|
17
13
|
redis("hset", "expected:count", "StandardError", 5)
|
18
14
|
redis("hset", "expected:count", "Custom::Error", 10)
|
@@ -80,7 +76,7 @@ module Sidekiq
|
|
80
76
|
get '/expected_failures'
|
81
77
|
last_response.body.must_match(/HardWorker/)
|
82
78
|
|
83
|
-
|
79
|
+
post '/expected_failures/clear', { what: 'all' }
|
84
80
|
last_response.status.must_equal(302)
|
85
81
|
last_response.location.must_match(/expected_failures$/)
|
86
82
|
|
@@ -93,7 +89,7 @@ module Sidekiq
|
|
93
89
|
last_response.body.must_match(/2013-09-10/)
|
94
90
|
last_response.body.must_match(/2013-09-09/)
|
95
91
|
|
96
|
-
|
92
|
+
post '/expected_failures/clear', { what: 'old' }
|
97
93
|
last_response.status.must_equal(302)
|
98
94
|
last_response.location.must_match(/expected_failures$/)
|
99
95
|
|
@@ -111,7 +107,7 @@ module Sidekiq
|
|
111
107
|
create_sample_failure
|
112
108
|
get '/expected_failures'
|
113
109
|
last_response.body.wont_match(/dl-horizontal/)
|
114
|
-
last_response.body.wont_match(/
|
110
|
+
last_response.body.wont_match(/All counters/i)
|
115
111
|
end
|
116
112
|
end
|
117
113
|
|
@@ -121,14 +117,14 @@ module Sidekiq
|
|
121
117
|
it 'displays counters' do
|
122
118
|
get '/expected_failures'
|
123
119
|
last_response.body.must_match(/dl-horizontal/)
|
124
|
-
last_response.body.must_match(/
|
120
|
+
last_response.body.must_match(/All counters/i)
|
125
121
|
end
|
126
122
|
|
127
123
|
it 'can clear counters' do
|
128
124
|
get '/expected_failures'
|
129
125
|
last_response.body.must_match(/Custom::Error/)
|
130
126
|
|
131
|
-
|
127
|
+
post '/expected_failures/clear', { what: 'counters' }
|
132
128
|
last_response.status.must_equal(302)
|
133
129
|
last_response.location.must_match(/expected_failures$/)
|
134
130
|
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
Coveralls.wear!
|
3
|
+
|
1
4
|
Encoding.default_external = Encoding::UTF_8
|
2
5
|
Encoding.default_internal = Encoding::UTF_8
|
3
6
|
|
4
7
|
require "minitest/autorun"
|
5
8
|
require "minitest/spec"
|
6
9
|
require "minitest/mock"
|
10
|
+
require "minitest/pride"
|
11
|
+
require "mocha/setup"
|
12
|
+
|
7
13
|
|
8
14
|
require "timecop"
|
9
15
|
require "rack/test"
|
data/test/test_workers.rb
CHANGED
@@ -8,10 +8,19 @@ end
|
|
8
8
|
|
9
9
|
class SingleExceptionWorker
|
10
10
|
include ::Sidekiq::Worker
|
11
|
-
sidekiq_options expected_failures:
|
11
|
+
sidekiq_options expected_failures: { ZeroDivisionError => nil }
|
12
12
|
end
|
13
13
|
|
14
14
|
class MultipleExceptionWorker
|
15
15
|
include ::Sidekiq::Worker
|
16
|
-
sidekiq_options expected_failures:
|
16
|
+
sidekiq_options expected_failures: { NotImplementedError => nil, VeryOwn::CustomException => nil }
|
17
|
+
end
|
18
|
+
|
19
|
+
class CustomizedWorker
|
20
|
+
include ::Sidekiq::Worker
|
21
|
+
sidekiq_options expected_failures: {
|
22
|
+
NotImplementedError => nil,
|
23
|
+
VeryOwn::CustomException => [10, 20, 50],
|
24
|
+
ZeroDivisionError => 5
|
25
|
+
}
|
17
26
|
end
|
data/web/assets/expected.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
<%=
|
1
|
+
<script type="text/javascript">
|
2
|
+
<%= @javascript %>
|
3
|
+
</script>
|
3
4
|
|
4
5
|
<h3>Expected failures log
|
5
6
|
<% if @date %>
|
@@ -8,9 +9,7 @@
|
|
8
9
|
</h3>
|
9
10
|
|
10
11
|
<% unless @counters.empty? %>
|
11
|
-
<div class="well well-sm
|
12
|
-
<a href="<%= root_path %>expected_failures/clear/counters" class="btn btn-default btn-sm pull-right">Clear counters</span></a>
|
13
|
-
|
12
|
+
<div class="well well-sm">
|
14
13
|
<dl class="dl-horizontal" style="margin: 0">
|
15
14
|
<% @counters.each do |exception, count| %>
|
16
15
|
<dt><%= exception %></dt>
|
@@ -21,6 +20,26 @@
|
|
21
20
|
</div>
|
22
21
|
<% end %>
|
23
22
|
|
23
|
+
<% if @jobs.any? || @counters.any? %>
|
24
|
+
<form id="clear-jobs" method="post" class="form-inline pull-right" action="<%= root_path %>expected_failures/clear">
|
25
|
+
<label>Clear:</label>
|
26
|
+
<select name="what">
|
27
|
+
<option selected>Choose...</option>
|
28
|
+
<% if @jobs.any? %>
|
29
|
+
<optgroup label="Jobs">
|
30
|
+
<option value="old">Older than today</option>
|
31
|
+
<option value="all">All failed</option>
|
32
|
+
</optgroup>
|
33
|
+
<% end %>
|
34
|
+
<% if @counters.any? %>
|
35
|
+
<optgroup label="Counters">
|
36
|
+
<option value="counters">All counters</option>
|
37
|
+
</optgroup>
|
38
|
+
<% end %>
|
39
|
+
</select>
|
40
|
+
</form>
|
41
|
+
<% end %>
|
42
|
+
|
24
43
|
<% if @jobs.any? %>
|
25
44
|
<div class="modal fade" id="job-details">
|
26
45
|
<div class="modal-dialog">
|
@@ -56,13 +75,10 @@
|
|
56
75
|
</select>
|
57
76
|
</form>
|
58
77
|
|
59
|
-
<div class="pull-right">
|
60
|
-
<a href="<%= root_path %>expected_failures/clear/old" class="btn btn-default btn-sm">Clear older than today</a>
|
61
|
-
<a href="<%= root_path %>expected_failures/clear/all" class="btn btn-default btn-sm">Clear all failed</a>
|
62
|
-
</div>
|
63
|
-
|
64
78
|
<p class="clearfix"></p>
|
65
79
|
|
80
|
+
<%= erb :_paging, :locals => { :url => "#{root_path}expected_failures/#{@date}" } %>
|
81
|
+
|
66
82
|
<table id="expected" class="queues table table-hover table-bordered table-striped table-white">
|
67
83
|
<thead>
|
68
84
|
<th>Datetime</th>
|
@@ -85,6 +101,7 @@
|
|
85
101
|
<%= erb :_paging, :locals => { :url => "#{root_path}expected_failures/#{@date}" } %>
|
86
102
|
|
87
103
|
<% else %>
|
104
|
+
<p class="clearfix"></p>
|
88
105
|
<div class="alert alert-success">
|
89
106
|
No failed jobs found.
|
90
107
|
</div>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-expected_failures
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sidekiq
|
@@ -27,22 +27,6 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 2.15.0
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: sinatra-assetpack
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 0.3.1
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 0.3.1
|
46
30
|
- !ruby/object:Gem::Dependency
|
47
31
|
name: bundler
|
48
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +107,38 @@ dependencies:
|
|
123
107
|
- - ~>
|
124
108
|
- !ruby/object:Gem::Version
|
125
109
|
version: 0.6.3
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: mocha
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.14.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.14.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: coveralls
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.7.0
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.7.0
|
126
142
|
description: If you don't rely on sidekiq' retry behavior, you handle exceptions on
|
127
143
|
your own and want to keep track of them - this thing is for you.
|
128
144
|
email:
|
@@ -166,7 +182,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
166
182
|
version: '0'
|
167
183
|
segments:
|
168
184
|
- 0
|
169
|
-
hash:
|
185
|
+
hash: 3929689485539629877
|
170
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
187
|
none: false
|
172
188
|
requirements:
|
@@ -175,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
175
191
|
version: '0'
|
176
192
|
segments:
|
177
193
|
- 0
|
178
|
-
hash:
|
194
|
+
hash: 3929689485539629877
|
179
195
|
requirements: []
|
180
196
|
rubyforge_project:
|
181
197
|
rubygems_version: 1.8.25
|