sidekiq-failures-discourse 0.3.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 +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +48 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +22 -0
- data/README.md +153 -0
- data/Rakefile +12 -0
- data/lib/sidekiq-failures.rb +1 -0
- data/lib/sidekiq/failures.rb +79 -0
- data/lib/sidekiq/failures/failure_set.rb +22 -0
- data/lib/sidekiq/failures/locales/en.yml +5 -0
- data/lib/sidekiq/failures/middleware.rb +99 -0
- data/lib/sidekiq/failures/sorted_entry.rb +14 -0
- data/lib/sidekiq/failures/version.rb +5 -0
- data/lib/sidekiq/failures/views/failure.erb +30 -0
- data/lib/sidekiq/failures/views/failures.erb +75 -0
- data/lib/sidekiq/failures/web_extension.rb +72 -0
- data/sidekiq-failures.gemspec +24 -0
- data/test/middleware_test.rb +283 -0
- data/test/test_helper.rb +20 -0
- data/test/web_extension_test.rb +209 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c480f406d6925142f99a976501f2388b6d1e1e00
|
4
|
+
data.tar.gz: c82a6b0f9d58f2d02edd54f5ea329d2ed72ff58a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 065f2dca2eaaacf33997b7365b2a3a429b69108b68b2c1a88eeb717d78fb06ac4729d34a74b240a72b312668d17d5c00ed8627c45f5e2ac6053c7b6cfea5a0a2
|
7
|
+
data.tar.gz: 22efa3a06a64125f18678fb456b40c1b99653554a7238fec7463c512d2783007d249a5e16b0d81644e296c17f71772c21c121471c9b50bd8200e59e9aca32f7f
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
## Unreleased
|
2
|
+
|
3
|
+
## 0.3.0
|
4
|
+
* Bump sidekiq dependency to sidekiq >= 2.14.0
|
5
|
+
* Remove slim templates and dependecy
|
6
|
+
* Escape exception info when outputing to html
|
7
|
+
* Add `Sidekiq::Failures.reset_failures` helper method
|
8
|
+
* Add `Sidekiq::Failures.count` helper method (@zanker)
|
9
|
+
* Adhere to sidekiq approach of showing UTC times
|
10
|
+
* Catch all exceptions, not just those that inherit from StandardError (@tylerkovacs)
|
11
|
+
* Fix private method call (@bwthomas)
|
12
|
+
|
13
|
+
## 0.2.2
|
14
|
+
* Support ERB for sidekiq >= 2.14.0 (@tobiassvn)
|
15
|
+
* Bump sidekiq dep to >= 2.9.0
|
16
|
+
* Show newest failures first (@PlugIN73)
|
17
|
+
* Fix specs (@krasnoukhov)
|
18
|
+
|
19
|
+
## 0.2.1
|
20
|
+
* Fix exhausted mode when retry is disabled (@wr0ngway)
|
21
|
+
|
22
|
+
## 0.2.0
|
23
|
+
* Added processor identity to failure data (@krasnoukhov)
|
24
|
+
* Handle Sidekiq::Shutdown exceptions (@krasnoukhov)
|
25
|
+
* Add failures maximum count option (@mathieulaporte)
|
26
|
+
* User Expception#message instead of Exception#to_s (@supaspoida)
|
27
|
+
* Removed web depencies (@LongMan)
|
28
|
+
* Stop overloading find_template (@zquestz)
|
29
|
+
|
30
|
+
## 0.1.0
|
31
|
+
* Allow per worker configuration of failure tracking mode. Thanks to
|
32
|
+
@kbaum for most of the work.
|
33
|
+
* Prevent sidekiq-failures from loading up sidekiq/processor (and thus
|
34
|
+
Celluloid actors) except for inside a Sidekiq server context (@cheald)
|
35
|
+
* Fix pagination bug
|
36
|
+
* Add failures default mode option (@kbaum)
|
37
|
+
* Add checkbox option to reset failed counter (@krasnoukhov)
|
38
|
+
|
39
|
+
## 0.0.3
|
40
|
+
|
41
|
+
* Adequate layout to new sidekiq web ui design (@krasnoukhov)
|
42
|
+
* Improve backtrace view (@krasnoukhov)
|
43
|
+
* Remove unnecessary slash in redirect (@krasnoukhov)
|
44
|
+
* Invert order of failed jobs (@krasnoukhov)
|
45
|
+
|
46
|
+
## 0.0.2
|
47
|
+
|
48
|
+
* Show backtrace similar to resque (Kunal Modi)
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sidekiq-failures-discourse (0.3.0)
|
5
|
+
sidekiq (>= 2.14.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
celluloid (0.15.2)
|
11
|
+
timers (~> 1.1.0)
|
12
|
+
connection_pool (2.0.0)
|
13
|
+
hike (1.2.1)
|
14
|
+
json (1.8.1)
|
15
|
+
multi_json (1.7.3)
|
16
|
+
rack (1.4.1)
|
17
|
+
rack-protection (1.2.0)
|
18
|
+
rack
|
19
|
+
rack-test (0.6.2)
|
20
|
+
rack (>= 1.0)
|
21
|
+
rake (0.9.2.2)
|
22
|
+
redis (3.0.7)
|
23
|
+
redis-namespace (1.4.1)
|
24
|
+
redis (~> 3.0.4)
|
25
|
+
sidekiq (3.0.0)
|
26
|
+
celluloid (>= 0.15.2)
|
27
|
+
connection_pool (>= 2.0.0)
|
28
|
+
json
|
29
|
+
redis (>= 3.0.6)
|
30
|
+
redis-namespace (>= 1.3.1)
|
31
|
+
sinatra (1.3.3)
|
32
|
+
rack (~> 1.3, >= 1.3.6)
|
33
|
+
rack-protection (~> 1.2)
|
34
|
+
tilt (~> 1.3, >= 1.3.3)
|
35
|
+
sprockets (2.8.1)
|
36
|
+
hike (~> 1.2)
|
37
|
+
multi_json (~> 1.0)
|
38
|
+
rack (~> 1.0)
|
39
|
+
tilt (~> 1.1, != 1.3.0)
|
40
|
+
tilt (1.3.3)
|
41
|
+
timers (1.1.0)
|
42
|
+
|
43
|
+
PLATFORMS
|
44
|
+
ruby
|
45
|
+
|
46
|
+
DEPENDENCIES
|
47
|
+
rack-test
|
48
|
+
rake
|
49
|
+
sidekiq-failures-discourse!
|
50
|
+
sinatra
|
51
|
+
sprockets
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Marcelo Silveira
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# Sidekiq::Failures [](http://travis-ci.org/mhfs/sidekiq-failures)
|
2
|
+
|
3
|
+
Keeps track of Sidekiq failed jobs and adds a tab to the Web UI to let you browse
|
4
|
+
them. Makes use of Sidekiq's custom tabs and middleware chain.
|
5
|
+
|
6
|
+
It mimics the way Resque keeps track of failures.
|
7
|
+
|
8
|
+
WARNING: by default sidekiq-failures will keep up to 1000 failures. See [Maximum Tracked Failures](https://github.com/mhfs/sidekiq-failures#maximum-tracked-failures) below.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'sidekiq-failures'
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Simply having the gem in your Gemfile is enough to get you started. Your failed
|
21
|
+
jobs will be visible via a Failures tab in the Web UI.
|
22
|
+
|
23
|
+
## Configuring
|
24
|
+
|
25
|
+
### Maximum Tracked Failures
|
26
|
+
|
27
|
+
Since each failed job/retry creates a new failure entry that will only be removed
|
28
|
+
by you manually, your failures list might consume more resources than you have
|
29
|
+
available.
|
30
|
+
|
31
|
+
To avoid this sidekiq-failures adopts a default of 1000 maximum tracked failures.
|
32
|
+
|
33
|
+
To change the maximum amount:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
Sidekiq.configure_server do |config|
|
37
|
+
config.failures_max_count = 5000
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
To disable the limit entirely:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
Sidekiq.configure_server do |config|
|
45
|
+
config.failures_max_count = false
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
### Failures Tracking Mode
|
50
|
+
|
51
|
+
Sidekiq-failures offers three failures tracking options (per worker):
|
52
|
+
|
53
|
+
|
54
|
+
#### :all (default)
|
55
|
+
|
56
|
+
Tracks failures every time a background job fails. This mean a job with 25 retries
|
57
|
+
enabled might generate up to 25 failure entries. If the worker has retry disabled
|
58
|
+
only one failure will be tracked.
|
59
|
+
|
60
|
+
This is the default behavior but can be made explicit with:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class MyWorker
|
64
|
+
include Sidekiq::Worker
|
65
|
+
|
66
|
+
sidekiq_options :failures => true # or :all
|
67
|
+
|
68
|
+
def perform; end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
#### :exhausted
|
73
|
+
|
74
|
+
Only track failures if the job exhausts all its retries (or doesn't have retries
|
75
|
+
enabled).
|
76
|
+
|
77
|
+
You can set this mode as follows:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
class MyWorker
|
81
|
+
include Sidekiq::Worker
|
82
|
+
|
83
|
+
sidekiq_options :failures => :exhausted
|
84
|
+
|
85
|
+
def perform; end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
#### :off
|
90
|
+
|
91
|
+
You can also completely turn off failures tracking for a given worker as follows:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class MyWorker
|
95
|
+
include Sidekiq::Worker
|
96
|
+
|
97
|
+
sidekiq_options :failures => false # or :off
|
98
|
+
|
99
|
+
def perform; end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
#### Change the default mode
|
104
|
+
|
105
|
+
You can also change the default of all your workers at once by setting the following
|
106
|
+
server config:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Sidekiq.configure_server do |config|
|
110
|
+
config.failures_default_mode = :off
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
The valid modes are `:all`, `:exhausted` or `:off`.
|
115
|
+
|
116
|
+
## Helper Methods
|
117
|
+
|
118
|
+
### Failures Count
|
119
|
+
|
120
|
+
Gives back the number of failed jobs currently stored in Sidekiq Failures. Notice that it's
|
121
|
+
different from `Sidekiq` built in failed stat. Also, notice that this might be
|
122
|
+
influenced by `failures_max_count`.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
Sidekiq::Failures.count
|
126
|
+
```
|
127
|
+
|
128
|
+
### Reset Failures
|
129
|
+
|
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.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
Sidekiq::Failures.reset_failures
|
135
|
+
```
|
136
|
+
|
137
|
+
## Dependencies
|
138
|
+
|
139
|
+
Depends on Sidekiq >= 2.14.0
|
140
|
+
|
141
|
+
## Contributing
|
142
|
+
|
143
|
+
1. Fork it
|
144
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
145
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
146
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
147
|
+
5. Create new Pull Request
|
148
|
+
|
149
|
+
## License
|
150
|
+
|
151
|
+
Released under the MIT License. See the [LICENSE][license] file for further details.
|
152
|
+
|
153
|
+
[license]: https://github.com/mhfs/sidekiq-failures/blob/master/LICENSE
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "sidekiq/failures"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
begin
|
2
|
+
require "sidekiq/web"
|
3
|
+
rescue LoadError
|
4
|
+
# client-only usage
|
5
|
+
end
|
6
|
+
|
7
|
+
require "sidekiq/api"
|
8
|
+
require "sidekiq/failures/version"
|
9
|
+
require "sidekiq/failures/sorted_entry"
|
10
|
+
require "sidekiq/failures/failure_set"
|
11
|
+
require "sidekiq/failures/middleware"
|
12
|
+
require "sidekiq/failures/web_extension"
|
13
|
+
|
14
|
+
module Sidekiq
|
15
|
+
|
16
|
+
SIDEKIQ_FAILURES_MODES = [:all, :exhausted, :off].freeze
|
17
|
+
|
18
|
+
# Sets the default failure tracking mode.
|
19
|
+
#
|
20
|
+
# The value provided here will be the default behavior but can be overwritten
|
21
|
+
# per worker by using `sidekiq_options :failures => :mode`
|
22
|
+
#
|
23
|
+
# Defaults to :all
|
24
|
+
def self.failures_default_mode=(mode)
|
25
|
+
unless SIDEKIQ_FAILURES_MODES.include?(mode.to_sym)
|
26
|
+
raise ArgumentError, "Sidekiq#failures_default_mode valid options: #{SIDEKIQ_FAILURES_MODES}"
|
27
|
+
end
|
28
|
+
|
29
|
+
@failures_default_mode = mode.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
# Fetches the default failure tracking mode.
|
33
|
+
def self.failures_default_mode
|
34
|
+
@failures_default_mode || :all
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets the maximum number of failures to track
|
38
|
+
#
|
39
|
+
# If the number of failures exceeds this number the list will be trimmed (oldest
|
40
|
+
# failures will be purged).
|
41
|
+
#
|
42
|
+
# Defaults to 1000
|
43
|
+
# Set to false to disable rotation
|
44
|
+
def self.failures_max_count=(value)
|
45
|
+
@failures_max_count = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fetches the failures max count value
|
49
|
+
def self.failures_max_count
|
50
|
+
return 1000 if @failures_max_count.nil?
|
51
|
+
|
52
|
+
@failures_max_count
|
53
|
+
end
|
54
|
+
|
55
|
+
module Failures
|
56
|
+
LIST_KEY = :failed
|
57
|
+
|
58
|
+
def self.reset_failures
|
59
|
+
Sidekiq.redis { |c| c.set("stat:failed", 0) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.count
|
63
|
+
Sidekiq.redis {|r| r.zcard(LIST_KEY) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Sidekiq.configure_server do |config|
|
69
|
+
config.server_middleware do |chain|
|
70
|
+
chain.insert_before Sidekiq::Middleware::Server::RetryJobs,
|
71
|
+
Sidekiq::Failures::Middleware
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if defined?(Sidekiq::Web)
|
76
|
+
Sidekiq::Web.register Sidekiq::Failures::WebExtension
|
77
|
+
Sidekiq::Web.tabs["Failures"] = "failures"
|
78
|
+
Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "failures/locales")
|
79
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Failures
|
3
|
+
Superclass =
|
4
|
+
if defined?(Sidekiq::JobSet)
|
5
|
+
Sidekiq::JobSet
|
6
|
+
else
|
7
|
+
Sidekiq::SortedSet
|
8
|
+
end
|
9
|
+
|
10
|
+
class FailureSet < Superclass
|
11
|
+
def initialize
|
12
|
+
super LIST_KEY
|
13
|
+
end
|
14
|
+
|
15
|
+
def retry_all_failures
|
16
|
+
while size > 0
|
17
|
+
each(&:retry_failure)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Failures
|
3
|
+
|
4
|
+
class Middleware
|
5
|
+
attr_accessor :msg
|
6
|
+
|
7
|
+
def call(worker, msg, queue)
|
8
|
+
self.msg = msg
|
9
|
+
yield
|
10
|
+
rescue Sidekiq::Shutdown
|
11
|
+
raise
|
12
|
+
rescue Exception => e
|
13
|
+
raise e if skip_failure?
|
14
|
+
|
15
|
+
msg['error_message'] = e.message
|
16
|
+
msg['error_class'] = e.class.name
|
17
|
+
msg['processor'] = identity
|
18
|
+
msg['failed_at'] = Time.now.utc.to_f
|
19
|
+
|
20
|
+
if msg['backtrace'] == true
|
21
|
+
msg['error_backtrace'] = e.backtrace
|
22
|
+
elsif msg['backtrace'] == false
|
23
|
+
# do nothing
|
24
|
+
elsif msg['backtrace'].to_i != 0
|
25
|
+
msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
|
26
|
+
end
|
27
|
+
|
28
|
+
payload = Sidekiq.dump_json(msg)
|
29
|
+
Sidekiq.redis do |conn|
|
30
|
+
conn.zadd(LIST_KEY, Time.now.utc.to_f, payload)
|
31
|
+
unless Sidekiq.failures_max_count == false
|
32
|
+
conn.zremrangebyrank(LIST_KEY, 0, -(Sidekiq.failures_max_count + 1))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
raise e
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def failure_mode_off?
|
42
|
+
failure_mode == :off
|
43
|
+
end
|
44
|
+
|
45
|
+
def failure_mode_exhausted?
|
46
|
+
failure_mode == :exhausted
|
47
|
+
end
|
48
|
+
|
49
|
+
def skip_failure?
|
50
|
+
failure_mode_off? || failure_mode_exhausted? && !exhausted?
|
51
|
+
end
|
52
|
+
|
53
|
+
def failure_mode
|
54
|
+
case msg['failures'].to_s
|
55
|
+
when 'true', 'all'
|
56
|
+
:all
|
57
|
+
when 'false', 'off'
|
58
|
+
:off
|
59
|
+
when 'exhausted'
|
60
|
+
:exhausted
|
61
|
+
else
|
62
|
+
Sidekiq.failures_default_mode
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def exhausted?
|
67
|
+
!retriable? || retry_count >= max_retries
|
68
|
+
end
|
69
|
+
|
70
|
+
def retriable?
|
71
|
+
msg['retry']
|
72
|
+
end
|
73
|
+
|
74
|
+
def retry_count
|
75
|
+
msg['retry_count'] || 0
|
76
|
+
end
|
77
|
+
|
78
|
+
def max_retries
|
79
|
+
retry_middleware.send(:retry_attempts_from, msg['retry'], default_max_retries)
|
80
|
+
end
|
81
|
+
|
82
|
+
def retry_middleware
|
83
|
+
@retry_middleware ||= Sidekiq::Middleware::Server::RetryJobs.new
|
84
|
+
end
|
85
|
+
|
86
|
+
def default_max_retries
|
87
|
+
Sidekiq::Middleware::Server::RetryJobs::DEFAULT_MAX_RETRY_ATTEMPTS
|
88
|
+
end
|
89
|
+
|
90
|
+
def hostname
|
91
|
+
Socket.gethostname
|
92
|
+
end
|
93
|
+
|
94
|
+
def identity
|
95
|
+
@@identity ||= "#{hostname}:#{$$}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|