sidekiq-undertaker 1.0.0.rc01
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +6 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +23 -0
- data/.travis.yml +53 -0
- data/Demo_Filter.png +0 -0
- data/Demo_Job_Filter.png +0 -0
- data/Demo_Morgue_1_Job.png +0 -0
- data/Demo_Morgue_all.png +0 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +95 -0
- data/Rakefile +34 -0
- data/lib/sidekiq/undertaker.rb +16 -0
- data/lib/sidekiq/undertaker/bucket.rb +29 -0
- data/lib/sidekiq/undertaker/dead_job.rb +64 -0
- data/lib/sidekiq/undertaker/job_distributor.rb +64 -0
- data/lib/sidekiq/undertaker/job_filter.rb +46 -0
- data/lib/sidekiq/undertaker/version.rb +7 -0
- data/lib/sidekiq/undertaker/web_extension.rb +37 -0
- data/lib/sidekiq/undertaker/web_extension/api_helpers.rb +120 -0
- data/sidekiq-undertaker.gemspec +55 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_filter_page_is_called/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +240 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_called/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +241 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_polled/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +241 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_all_failures_and_errors/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +316 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_specific_job_class_and_a_specific_error/behaves_like_a_page/the_displayed_page_is_correct.approved.txt +274 -0
- data/spec/sidekiq/undertaker/bucket_spec.rb +26 -0
- data/spec/sidekiq/undertaker/dead_jobs_spec.rb +90 -0
- data/spec/sidekiq/undertaker/job_distributor_spec.rb +104 -0
- data/spec/sidekiq/undertaker/job_filter_spec.rb +105 -0
- data/spec/sidekiq/undertaker/web_extension_spec.rb +270 -0
- data/spec/spec_helper.rb +76 -0
- data/web/locales/en.yml +5 -0
- data/web/views/filter.erb +34 -0
- data/web/views/filter_job_class.erb +35 -0
- data/web/views/morgue.erb +75 -0
- metadata +378 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 11a061d4335309c54a17ef8f34fc207c49a36ad772f74a145b15482d2dc4446e
|
4
|
+
data.tar.gz: b82c5d0d70efd96d4e32e9e1ef6e402f2ccce912bfe50ad4b7ea1ddf97b1c463
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dba278326f094e4a3498f727791bc484e2e960be1d751f044a209a8f18583890e3cae95368692618eff8d4b315046806d94c24887a24b64b1b000d09f4f8f0d9
|
7
|
+
data.tar.gz: 48b3d817160a12606fec4a7f160c7b29062aca67bebcafc54ba8953a668c75ecf9b3cacf81f8e7315a2fd5abfa5a723d41e70e5b7b6fb50fd234bc7b5cb148fa
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
_yardoc
|
2
|
+
.approvals
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.idea/
|
6
|
+
.ruby-version
|
7
|
+
.rvmrc
|
8
|
+
.yardoc
|
9
|
+
*.gem
|
10
|
+
*.rbc
|
11
|
+
*.received.*
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
Gemfile.lock
|
15
|
+
InstalledFiles
|
16
|
+
lib/bundler/man
|
17
|
+
pkg
|
18
|
+
rdoc
|
19
|
+
spec/reports
|
20
|
+
test/tmp
|
21
|
+
test/version_tmp
|
22
|
+
tmp
|
data/.rubocop.yml
ADDED
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2019-12-06 21:33:12 +0100 using RuboCop version 0.77.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 2
|
10
|
+
# Configuration parameters: Severity.
|
11
|
+
Metrics/AbcSize:
|
12
|
+
Max: 22
|
13
|
+
|
14
|
+
# Offense count: 3
|
15
|
+
# Configuration parameters: CountComments, ExcludedMethods, Severity.
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Max: 19
|
18
|
+
|
19
|
+
# Offense count: 5
|
20
|
+
# Configuration parameters: .
|
21
|
+
# SupportedStyles: have_received, receive
|
22
|
+
RSpec/MessageSpies:
|
23
|
+
EnforcedStyle: receive
|
data/.travis.yml
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
rvm:
|
4
|
+
- 2.4.9
|
5
|
+
- 2.5.7
|
6
|
+
- 2.6.5
|
7
|
+
- jruby-9.1.17.0
|
8
|
+
- jruby-9.2.9.0
|
9
|
+
jdk:
|
10
|
+
- oraclejdk11
|
11
|
+
env:
|
12
|
+
global:
|
13
|
+
- CC_TEST_REPORTER_ID=9fd6c503f8bb89483410c1fc0578e5845c3fe0d3e773a32eb2788713fb101a93
|
14
|
+
matrix:
|
15
|
+
- "JRUBY_OPTS='--dev --debug'"
|
16
|
+
- "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
17
|
+
|
18
|
+
matrix:
|
19
|
+
exclude:
|
20
|
+
- rvm: 2.4.9
|
21
|
+
jdk: oraclejdk8
|
22
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
23
|
+
- rvm: 2.5.7
|
24
|
+
jdk: oraclejdk8
|
25
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
26
|
+
- rvm: 2.6.5
|
27
|
+
jdk: oraclejdk8
|
28
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
29
|
+
- rvm: truffleruby
|
30
|
+
jdk: oraclejdk8
|
31
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
32
|
+
allow_failures:
|
33
|
+
- rvm: jruby-9.1.17.0
|
34
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
35
|
+
- rvm: jruby-9.2.9.0
|
36
|
+
env: "JRUBY_OPTS='-Xcompile.invokedynamic=true --debug'"
|
37
|
+
|
38
|
+
services:
|
39
|
+
- redis-server
|
40
|
+
|
41
|
+
before_install:
|
42
|
+
- gem update --system
|
43
|
+
- gem install bundler -v "~> 1.0"
|
44
|
+
- gem install bundler -v "~> 2.0"
|
45
|
+
|
46
|
+
before_script:
|
47
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
48
|
+
- chmod +x ./cc-test-reporter
|
49
|
+
- ./cc-test-reporter before-build
|
50
|
+
script:
|
51
|
+
- COVERAGE=true bundle exec rspec
|
52
|
+
after_script:
|
53
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Demo_Filter.png
ADDED
Binary file
|
data/Demo_Job_Filter.png
ADDED
Binary file
|
Binary file
|
data/Demo_Morgue_all.png
ADDED
Binary file
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in sidekiq-undertaker.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
# Good for debuging on travis-ci.org
|
9
|
+
# group :development, :test do
|
10
|
+
# gem "approvals", git: "https://github.com/br/approvals", branch: "diff-preview"
|
11
|
+
# end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2019 Thomas Koppensteiner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Sidekiq::Undertaker
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ThomasKoppensteiner/sidekiq-under.svg?branch=master)](https://travis-ci.org/ThomasKoppensteiner/sidekiq-undertaker)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker.svg)](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker)
|
5
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/9d75b8b7d3ff076e1ef1/test_coverage)](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker/test_coverage)
|
6
|
+
|
7
|
+
## About
|
8
|
+
|
9
|
+
Sidekiq::Undertaker is a plugin for [Sidekiq](https://rubygems.org/gems/sidekiq).
|
10
|
+
It allows exploring, reviving (retrying) or burying (deleting) dead jobs.
|
11
|
+
For easy exploring the dead-jobs queue is broken down into time windows (buckets) of hours, days and weeks.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
#### Install the Gem
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
````ruby
|
20
|
+
gem "sidekiq-undertaker"
|
21
|
+
````
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
````sh
|
25
|
+
$ bundle
|
26
|
+
````
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
````sh
|
31
|
+
$ gem install sidekiq-undertaker
|
32
|
+
````
|
33
|
+
|
34
|
+
#### Install the Rubocop Pre-Commit Hook
|
35
|
+
|
36
|
+
````sh
|
37
|
+
$ rake rubocop:install
|
38
|
+
````
|
39
|
+
|
40
|
+
## Impressions
|
41
|
+
|
42
|
+
#### Filter View
|
43
|
+
|
44
|
+
The filter page shows a table with time-buckets as columns and rows for each job class.
|
45
|
+
|
46
|
+
![Sidekiq Undertaker](Demo_Filter.png)
|
47
|
+
|
48
|
+
#### Job Filter View
|
49
|
+
|
50
|
+
For each job class, you can drill down to view error distribution based on
|
51
|
+
error class.
|
52
|
+
|
53
|
+
![Sidekiq Undertaker](Demo_Job_Filter.png)
|
54
|
+
|
55
|
+
#### Morgue View
|
56
|
+
Finally, click on the individual error counts to display details of the
|
57
|
+
errors in a list form.
|
58
|
+
|
59
|
+
![Sidekiq Undertaker](Demo_Morgue_1_Job.png)
|
60
|
+
|
61
|
+
The morgue view can, for example, also show an error distribution over all job classes.
|
62
|
+
|
63
|
+
![Sidekiq Undertaker](Demo_Morgue_all.png)
|
64
|
+
|
65
|
+
## Contributing
|
66
|
+
|
67
|
+
1. Fork it ( https://github.com/ThomasKoppensteiner/sidekiq-undertaker/fork )
|
68
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
69
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
71
|
+
5. Create new Pull Request
|
72
|
+
|
73
|
+
## Naming
|
74
|
+
|
75
|
+
As another gem with the name `sidekiq-cleaner` is already released on rubygems.org,
|
76
|
+
this fork was renamed to `sidekiq-undertaker`.
|
77
|
+
|
78
|
+
## Thanks
|
79
|
+
|
80
|
+
The [Sidekiq-Cleaner](https://github.com/HackingHabits/sidekiq-cleaner) gem was originally created by [Madan Thangavelu](https://github.com/HackingHabits).
|
81
|
+
[Tout](https://github.com/Tout/sidekiq-cleaner) and [TheWudu](https://github.com/TheWudu/sidekiq-cleaner) also contributed to it.
|
82
|
+
For the complete list of network members have a look at the [fork overview](https://github.com/ThomasKoppensteiner/sidekiq-under/network/members).
|
83
|
+
|
84
|
+
## Alternative Projects
|
85
|
+
|
86
|
+
* [sidekiq-cleaner](https://rubygems.org/gems/sidekiq-cleaner)
|
87
|
+
* [sidekiq_cleaner](https://rubygems.org/gems/sidekiq_cleaner)
|
88
|
+
|
89
|
+
## Author
|
90
|
+
|
91
|
+
Thomas Koppensteiner | [Github](https://github.com/ThomasKoppensteiner) | [RubyGems](https://rubygems.org/profiles/thomaskoppensteiner) | [@koppensteiner_t](https://twitter.com/koppensteiner_t)
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
See the [License](https://github.com/ThomasKoppensteiner/sidekiq-under/blob/master/LICENSE.txt) file.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift("lib")
|
6
|
+
|
7
|
+
desc "setup gem for development"
|
8
|
+
task :init do
|
9
|
+
Rake::Task["rubocop:install"].execute
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# RubocopRunner
|
14
|
+
#
|
15
|
+
begin
|
16
|
+
require "rubocop_runner/rake_task"
|
17
|
+
RubocopRunner::RakeTask.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "RubocopRunner not available!"
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# RSpec
|
24
|
+
#
|
25
|
+
begin
|
26
|
+
require "rspec/core/rake_task"
|
27
|
+
|
28
|
+
RSpec::Core::RakeTask.new(:spec)
|
29
|
+
|
30
|
+
task default: :spec
|
31
|
+
task test: :spec
|
32
|
+
rescue LoadError
|
33
|
+
puts "RSpec not available!"
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/version"
|
4
|
+
require "sidekiq/undertaker/web_extension"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "sidekiq/web"
|
8
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
9
|
+
# client-only usage
|
10
|
+
end
|
11
|
+
|
12
|
+
if defined?(Sidekiq::Web)
|
13
|
+
Sidekiq::Web.register Sidekiq::Undertaker::WebExtension
|
14
|
+
Sidekiq::Web.tabs["Undertaker"] = "undertaker/filter"
|
15
|
+
Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "../../web/locales")
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
module Undertaker
|
5
|
+
class Bucket
|
6
|
+
class << self
|
7
|
+
def bucket_names
|
8
|
+
%w[1_hour 3_hours 1_day 3_days 1_week older]
|
9
|
+
end
|
10
|
+
|
11
|
+
def for_elapsed_time(elapsed_time)
|
12
|
+
return "1_hour" if elapsed_time <= ONE_HOUR
|
13
|
+
return "3_hours" if elapsed_time <= THREE_HOURS
|
14
|
+
return "1_day" if elapsed_time <= ONE_DAY
|
15
|
+
return "3_days" if elapsed_time <= THREE_DAYS
|
16
|
+
return "1_week" if elapsed_time <= ONE_WEEK
|
17
|
+
|
18
|
+
"older"
|
19
|
+
end
|
20
|
+
|
21
|
+
ONE_HOUR = 60 * 60 * 1
|
22
|
+
THREE_HOURS = ONE_HOUR * 3
|
23
|
+
ONE_DAY = ONE_HOUR * 24
|
24
|
+
THREE_DAYS = ONE_DAY * 3
|
25
|
+
ONE_WEEK = ONE_DAY * 7
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/bucket"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module Undertaker
|
7
|
+
class DeadJob
|
8
|
+
class << self
|
9
|
+
def for_each
|
10
|
+
Sidekiq::DeadSet.new.each do |job|
|
11
|
+
yield to_dead_job(job)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_dead_job(job)
|
16
|
+
job_failed_at = parsed_failed_at(job)
|
17
|
+
job_time_elapsed_since_failure = Time.now.to_i - job_failed_at.to_i
|
18
|
+
job_bucket_name = Bucket.for_elapsed_time(job_time_elapsed_since_failure)
|
19
|
+
|
20
|
+
new(job: job,
|
21
|
+
time_elapsed_since_failure: job_time_elapsed_since_failure,
|
22
|
+
bucket_name: job_bucket_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def parsed_failed_at(job)
|
26
|
+
job.item["failed_at"].is_a?(String) ? Time.parse(job.item["failed_at"]) : job.item["failed_at"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :job_class, :time_elapsed_since_failure, :error_class, :bucket_name, :job
|
31
|
+
|
32
|
+
def initialize(args)
|
33
|
+
@job = args.fetch(:job)
|
34
|
+
@time_elapsed_since_failure = args.fetch(:time_elapsed_since_failure)
|
35
|
+
@bucket_name = args.fetch(:bucket_name)
|
36
|
+
@job_class = args.fetch(:job_class, job.item["class"])
|
37
|
+
@error_class = args.fetch(:error_class, job.item["error_class"])
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
job_class == other.job_class &&
|
42
|
+
time_elapsed_since_failure == other.time_elapsed_since_failure &&
|
43
|
+
error_class == other.error_class &&
|
44
|
+
bucket_name == other.bucket_name &&
|
45
|
+
job_eql?(other.job)
|
46
|
+
end
|
47
|
+
alias eql? ==
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_writer :job_class, :time_elapsed_since_failure, :error_class, :bucket_name, :job
|
52
|
+
|
53
|
+
def job_eql?(other_job) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
54
|
+
job.jid == other_job.jid &&
|
55
|
+
job.item == other_job.item &&
|
56
|
+
job.args == other_job.args &&
|
57
|
+
job.queue == other_job.queue &&
|
58
|
+
job.score == other_job.score &&
|
59
|
+
job.parent.name == other_job.parent.name &&
|
60
|
+
job.parent.size == other_job.parent.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq/undertaker/bucket"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module Undertaker
|
7
|
+
class JobDistributor
|
8
|
+
attr_reader :dead_jobs
|
9
|
+
|
10
|
+
def initialize(dead_jobs)
|
11
|
+
@dead_jobs = dead_jobs
|
12
|
+
end
|
13
|
+
|
14
|
+
def group_by_job_class
|
15
|
+
group_by(:job_class)
|
16
|
+
end
|
17
|
+
|
18
|
+
def group_by_error_class
|
19
|
+
group_by(:error_class)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def distribute
|
25
|
+
distribution = init_counters({}, "all")
|
26
|
+
|
27
|
+
dead_jobs.each do |dead_job|
|
28
|
+
bucket_name = dead_job.bucket_name
|
29
|
+
|
30
|
+
incr_counters(distribution, "all", bucket_name)
|
31
|
+
yield distribution, dead_job, bucket_name if block_given?
|
32
|
+
end
|
33
|
+
|
34
|
+
sort_by_total_dead(distribution)
|
35
|
+
end
|
36
|
+
|
37
|
+
def group_by(attribute)
|
38
|
+
distribute do |distribution, dead_job, bucket_name|
|
39
|
+
attr = dead_job.public_send(attribute)
|
40
|
+
init_counters(distribution, attr) unless distribution[attr]
|
41
|
+
incr_counters(distribution, attr, bucket_name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def sort_by_total_dead(distribution)
|
46
|
+
distribution.map { |k, v| [k, v] }.sort do |x, y|
|
47
|
+
x[1]["total_dead"] <=> y[1]["total_dead"]
|
48
|
+
end.reverse
|
49
|
+
end
|
50
|
+
|
51
|
+
def init_counters(distribution, attr)
|
52
|
+
distribution[attr] = {}
|
53
|
+
Bucket.bucket_names.each { |bucket| distribution[attr][bucket] = 0 }
|
54
|
+
distribution[attr]["total_dead"] = 0
|
55
|
+
distribution
|
56
|
+
end
|
57
|
+
|
58
|
+
def incr_counters(distribution, attr, bucket_name, value = 1)
|
59
|
+
distribution[attr][bucket_name] += value
|
60
|
+
distribution[attr]["total_dead"] += value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|