sidekiq-undertaker 1.1.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby-build.yml +31 -3
- data/.rubocop.yml +4 -0
- data/.rubocop_codeclimate.yml +9 -0
- data/CHANGELOG.md +19 -0
- data/README.md +8 -6
- data/assets/Undertaker_demo_1_job_1_error.png +0 -0
- data/assets/Undertaker_demo_1_job_all_errors.png +0 -0
- data/assets/Undertaker_demo_all_errors.png +0 -0
- data/assets/Undertaker_demo_all_jobs.png +0 -0
- data/assets/Undertaker_demo_all_jobs_1_error.png +0 -0
- data/lib/sidekiq/undertaker/dead_job.rb +10 -2
- data/lib/sidekiq/undertaker/job_distributor.rb +4 -0
- data/lib/sidekiq/undertaker/job_filter.rb +7 -2
- data/lib/sidekiq/undertaker/version.rb +1 -1
- data/lib/sidekiq/undertaker/web_extension/api_helpers.rb +104 -26
- data/lib/sidekiq/undertaker/web_extension.rb +17 -8
- data/sidekiq-undertaker.gemspec +6 -5
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_filter_page_is_called/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +32 -18
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_called/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +37 -39
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classbucket_page_is_polled/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +37 -39
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classerror_classbucket_page_is_called/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +231 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_filter/when_job_classerror_classbucket_page_is_polled/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +231 -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_for_sidekiqv6.approved.txt +26 -21
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_job_class_error_and_specific_error_message/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +284 -0
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_job_class_error_and_specific_error_message/with_pagination/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +1310 -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_for_sidekiqv6.approved.txt +24 -19
- data/spec/fixtures/approvals/sidekiq_undertaker_webextension/show_morgue/when_job_classerrorbucket_is_called/with_specific_job_class_and_a_specific_error/with_pagination/behaves_like_a_page/the_displayed_page_is_correct_for_sidekiqv6.approved.txt +72 -67
- data/spec/sidekiq/undertaker/dead_jobs_spec.rb +7 -4
- data/spec/sidekiq/undertaker/job_distributor_spec.rb +41 -19
- data/spec/sidekiq/undertaker/job_filter_spec.rb +26 -9
- data/spec/sidekiq/undertaker/web_extension_spec.rb +172 -14
- data/spec/spec_helper.rb +4 -0
- data/web/locales/en.yml +2 -0
- data/web/views/filter.erb +17 -1
- data/web/views/filter_job_class.erb +8 -8
- data/web/views/filter_job_class_error_class.erb +36 -0
- data/web/views/morgue.erb +9 -2
- metadata +38 -30
- data/.travis.yml +0 -51
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9faade9f819fcaff3bc2246d68197d085f6f90b10b82f38290f5a3cc5752f07
|
4
|
+
data.tar.gz: c08b3349474057a180eecf4cc64b0bb15f43112b264833bc6f9441b5ee139549
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d5e1d644890b7ef70348f41faf14961852f76f41dbd3ee9f3fd85a57fc29ee97a3476e2bf224a41f6e76ec17219e7e7ac04abcd6f569fee956883c0b72ad786
|
7
|
+
data.tar.gz: df1f8590c18238ed71a20d380510375f0eba41ea07e2cfd49d4f1e2f3bd0d2d8f3aad43b0bb07fcea9d44dbd242ef0551e93bc3b5091d470d39d3e12e86b0fcf
|
@@ -34,12 +34,15 @@ jobs:
|
|
34
34
|
- '2.7'
|
35
35
|
- 'jruby'
|
36
36
|
- 'jruby-9.3.2.0'
|
37
|
-
- 'jruby-9.2.20.
|
37
|
+
- 'jruby-9.2.20.1'
|
38
38
|
- 'truffleruby'
|
39
39
|
- 'truffleruby+graalvm'
|
40
40
|
|
41
|
+
env:
|
42
|
+
JRUBY_OPTS: '--debug'
|
43
|
+
|
41
44
|
steps:
|
42
|
-
- uses: actions/checkout@
|
45
|
+
- uses: actions/checkout@v3
|
43
46
|
- name: Set up Ruby
|
44
47
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
45
48
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
@@ -48,4 +51,29 @@ jobs:
|
|
48
51
|
ruby-version: ${{ matrix.ruby-version }}
|
49
52
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
50
53
|
- name: Run tests
|
51
|
-
run: bundle exec rspec
|
54
|
+
run: COVERAGE=true bundle exec rspec
|
55
|
+
- name: 'Upload Coverage Report'
|
56
|
+
uses: actions/upload-artifact@v3
|
57
|
+
if: ${{ matrix.ruby-version == 'ruby' }}
|
58
|
+
with:
|
59
|
+
name: coverage-report
|
60
|
+
path: ./coverage
|
61
|
+
retention-days: 1
|
62
|
+
|
63
|
+
coverage:
|
64
|
+
needs: [ test ]
|
65
|
+
name: coverage
|
66
|
+
runs-on: ubuntu-latest
|
67
|
+
steps:
|
68
|
+
- uses: actions/checkout@v3
|
69
|
+
- name: Download Coverage Report
|
70
|
+
uses: actions/download-artifact@v3
|
71
|
+
with:
|
72
|
+
name: coverage-report
|
73
|
+
path: ./coverage
|
74
|
+
- uses: paambaati/codeclimate-action@v3.0.0
|
75
|
+
env:
|
76
|
+
# Set CC_TEST_REPORTER_ID as secret of your repo
|
77
|
+
CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
|
78
|
+
with:
|
79
|
+
debug: true
|
data/.rubocop.yml
CHANGED
data/.rubocop_codeclimate.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,25 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## [1.4.0] - 2022-06-03
|
6
|
+
### Added
|
7
|
+
- Added a filter based on error messages
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- Updated rubocop to version 1.30
|
11
|
+
- Updated rubyzip to version 2.3
|
12
|
+
|
13
|
+
### Removed
|
14
|
+
- Removed Travis CI integration
|
15
|
+
|
16
|
+
## [1.3.0] - 2022-04-27
|
17
|
+
### Added
|
18
|
+
- Added option to export and re-import dead jobs
|
19
|
+
|
20
|
+
## [1.2.0] - 2022-02-03
|
21
|
+
### Changed
|
22
|
+
- Updated sidekiq dependency to 6.4.0
|
23
|
+
|
5
24
|
## [1.1.1] - 2022-02-03
|
6
25
|
### Added
|
7
26
|
- Added CHANGELOG.md
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Sidekiq::Undertaker
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/sidekiq-undertaker.svg)](https://badge.fury.io/rb/sidekiq-undertaker)
|
4
|
-
[![Build
|
4
|
+
[![Ruby-Build](https://github.com/ThomasKoppensteiner/sidekiq-undertaker/actions/workflows/ruby-build.yml/badge.svg)](https://github.com/ThomasKoppensteiner/sidekiq-undertaker/actions/workflows/ruby-build.yml)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker.svg)](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker)
|
6
6
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/d442eb0a323d8911661f/test_coverage)](https://codeclimate.com/github/ThomasKoppensteiner/sidekiq-undertaker/test_coverage)
|
7
7
|
[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop)
|
@@ -45,24 +45,24 @@ Or install it yourself as:
|
|
45
45
|
|
46
46
|
The filter page shows a table with time-buckets as columns and rows for each job class.
|
47
47
|
|
48
|
-
![Sidekiq Undertaker](
|
48
|
+
![Sidekiq Undertaker](assets/Undertaker_demo_all_jobs.png)
|
49
49
|
|
50
50
|
#### Job Filter View
|
51
51
|
|
52
52
|
For each job class, you can drill down to view error distribution based on
|
53
53
|
error class.
|
54
54
|
|
55
|
-
![Sidekiq Undertaker](
|
55
|
+
![Sidekiq Undertaker](assets/Undertaker_demo_1_job_all_errors.png)
|
56
56
|
|
57
57
|
#### Morgue View
|
58
58
|
Finally, click on the individual error counts to display details of the
|
59
59
|
errors in a list form.
|
60
60
|
|
61
|
-
![Sidekiq Undertaker](
|
61
|
+
![Sidekiq Undertaker](assets/Undertaker_demo_1_job_1_error.png)
|
62
62
|
|
63
63
|
The morgue view can, for example, also show an error distribution over all job classes.
|
64
64
|
|
65
|
-
![Sidekiq Undertaker](
|
65
|
+
![Sidekiq Undertaker](assets/Undertaker_demo_all_jobs_1_error.png)
|
66
66
|
|
67
67
|
## Contributing
|
68
68
|
|
@@ -81,7 +81,9 @@ this fork was renamed to `sidekiq-undertaker`.
|
|
81
81
|
|
82
82
|
The [Sidekiq-Cleaner](https://github.com/HackingHabits/sidekiq-cleaner) gem was originally created by [Madan Thangavelu](https://github.com/HackingHabits).
|
83
83
|
[Tout](https://github.com/Tout/sidekiq-cleaner) and [TheWudu](https://github.com/TheWudu/sidekiq-cleaner) also contributed to it.
|
84
|
-
|
84
|
+
[Zlatko Rednjak](https://github.com/Rednjak) added the initial version of the `CHANGELOG.md`.
|
85
|
+
[Lucas Dell'Isola](https://github.com/ldellisola) added the export/import feature for dead jobs.
|
86
|
+
[thoesl](https://github.com/thoesl) added the error message based filter.
|
85
87
|
|
86
88
|
For the complete list of network members have a look at the [fork overview](https://github.com/ThomasKoppensteiner/sidekiq-undertaker/network/members).
|
87
89
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -27,7 +27,7 @@ module Sidekiq
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
attr_reader :job_class, :time_elapsed_since_failure, :error_class, :bucket_name, :job
|
30
|
+
attr_reader :job_class, :time_elapsed_since_failure, :error_class, :error_msg, :bucket_name, :job
|
31
31
|
|
32
32
|
def initialize(args)
|
33
33
|
@job = args.fetch(:job)
|
@@ -35,12 +35,14 @@ module Sidekiq
|
|
35
35
|
@bucket_name = args.fetch(:bucket_name)
|
36
36
|
@job_class = args.fetch(:job_class, job.item["class"])
|
37
37
|
@error_class = args.fetch(:error_class, job.item["error_class"])
|
38
|
+
@error_msg = shorten_error_msg(args.fetch(:error_message, job.item["error_message"]).to_s)
|
38
39
|
end
|
39
40
|
|
40
41
|
def ==(other)
|
41
42
|
job_class == other.job_class &&
|
42
43
|
time_elapsed_since_failure == other.time_elapsed_since_failure &&
|
43
44
|
error_class == other.error_class &&
|
45
|
+
error_msg == other.error_msg &&
|
44
46
|
bucket_name == other.bucket_name &&
|
45
47
|
job_eql?(other.job)
|
46
48
|
end
|
@@ -48,7 +50,13 @@ module Sidekiq
|
|
48
50
|
|
49
51
|
private
|
50
52
|
|
51
|
-
attr_writer :job_class, :time_elapsed_since_failure, :error_class, :bucket_name, :job
|
53
|
+
attr_writer :job_class, :time_elapsed_since_failure, :error_class, :error_message, :bucket_name, :job
|
54
|
+
|
55
|
+
def shorten_error_msg(msg)
|
56
|
+
max_error_msg_length = 30
|
57
|
+
|
58
|
+
msg.length > max_error_msg_length ? "#{msg[0, max_error_msg_length]}..." : msg
|
59
|
+
end
|
52
60
|
|
53
61
|
def job_eql?(other_job) # rubocop:disable Metrics/AbcSize
|
54
62
|
job.jid == other_job.jid &&
|
@@ -7,7 +7,7 @@ module Sidekiq
|
|
7
7
|
class JobFilter
|
8
8
|
class << self
|
9
9
|
def filter_dead_jobs(filters = {})
|
10
|
-
# filters can have keys in (job_class, error_class, bucket_name)
|
10
|
+
# filters can have keys in (job_class, error_class, error_msg, bucket_name)
|
11
11
|
dead_jobs = []
|
12
12
|
Sidekiq::Undertaker::DeadJob.for_each do |dead_job|
|
13
13
|
filter_passed = true
|
@@ -26,7 +26,8 @@ module Sidekiq
|
|
26
26
|
value.nil? ||
|
27
27
|
total_dead_bucket?(filter, value) ||
|
28
28
|
all_jobs?(filter, value) ||
|
29
|
-
all_errors?(filter, value)
|
29
|
+
all_errors?(filter, value) ||
|
30
|
+
all_error_msgs?(filter, value)
|
30
31
|
end
|
31
32
|
|
32
33
|
def total_dead_bucket?(filter, value)
|
@@ -40,6 +41,10 @@ module Sidekiq
|
|
40
41
|
def all_errors?(filter, value)
|
41
42
|
filter == "error_class" && value == "all"
|
42
43
|
end
|
44
|
+
|
45
|
+
def all_error_msgs?(filter, value)
|
46
|
+
filter == "error_msg" && value == "all"
|
47
|
+
end
|
43
48
|
end
|
44
49
|
end
|
45
50
|
end
|
@@ -2,15 +2,21 @@
|
|
2
2
|
|
3
3
|
require "sidekiq/undertaker/job_distributor"
|
4
4
|
require "sidekiq/undertaker/job_filter"
|
5
|
+
require "base64"
|
6
|
+
require "json"
|
7
|
+
require "zip"
|
5
8
|
|
6
9
|
module Sidekiq
|
7
10
|
module Undertaker
|
8
11
|
module WebExtension
|
12
|
+
# rubocop:disable Metrics/ModuleLength
|
9
13
|
module APIHelpers
|
14
|
+
EXPORT_CHUNK_SIZE = 2000
|
15
|
+
|
10
16
|
def show_filter
|
11
17
|
store_request_params
|
12
18
|
|
13
|
-
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(
|
19
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
14
20
|
@distribution = Sidekiq::Undertaker::JobDistributor.new(@dead_jobs).group_by_job_class
|
15
21
|
@total_dead = @dead_jobs.size
|
16
22
|
|
@@ -20,17 +26,27 @@ module Sidekiq
|
|
20
26
|
def show_filter_by_job_class_bucket_name
|
21
27
|
store_request_params
|
22
28
|
|
23
|
-
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(
|
29
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
24
30
|
@distribution = Sidekiq::Undertaker::JobDistributor.new(@dead_jobs).group_by_error_class
|
25
31
|
@total_dead = @dead_jobs.size
|
26
32
|
|
27
33
|
render_result("filter_job_class.erb")
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
36
|
+
def show_filter_by_job_class_error_class_bucket_name
|
37
|
+
store_request_params
|
38
|
+
|
39
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
40
|
+
@distribution = Sidekiq::Undertaker::JobDistributor.new(@dead_jobs).group_by_error_msg
|
41
|
+
@total_dead = @dead_jobs.size
|
42
|
+
|
43
|
+
render_result("filter_job_class_error_class.erb")
|
44
|
+
end
|
45
|
+
|
46
|
+
def show_undertaker_by_job_class_error_class_error_msg_bucket_name
|
31
47
|
store_request_params
|
32
48
|
|
33
|
-
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(
|
49
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
34
50
|
|
35
51
|
# Display dead jobs as list
|
36
52
|
@dead_jobs = @dead_jobs.map(&:job)
|
@@ -39,7 +55,7 @@ module Sidekiq
|
|
39
55
|
|
40
56
|
# Pagination
|
41
57
|
@total_dead = @dead_jobs.size
|
42
|
-
@current_page = (
|
58
|
+
@current_page = (parsed_params[:page] || 1).to_i
|
43
59
|
@count = 50 # per page
|
44
60
|
@dead_jobs = @dead_jobs[((@current_page - 1) * @count), @count]
|
45
61
|
|
@@ -52,32 +68,36 @@ module Sidekiq
|
|
52
68
|
params.delete("job_class")
|
53
69
|
params.delete("bucket_name")
|
54
70
|
params.delete("error_class")
|
71
|
+
params.delete("error_msg")
|
55
72
|
|
56
73
|
render_result("morgue.erb")
|
57
74
|
end
|
58
75
|
|
59
76
|
def post_undertaker
|
60
|
-
raise ::ArgumentError.new("Key missing") unless
|
61
|
-
|
62
|
-
params["key"].each do |key|
|
63
|
-
job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
|
64
|
-
if job
|
65
|
-
if params["retry"]
|
66
|
-
job.retry
|
67
|
-
elsif params["delete"]
|
68
|
-
job.delete
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
77
|
+
raise ::ArgumentError.new("Key missing") unless parsed_params["key"]
|
72
78
|
|
73
|
-
|
79
|
+
jobs = parsed_params["key"].map { |k| Sidekiq::DeadSet.new.fetch(*parse_params(k)).first }.compact
|
80
|
+
|
81
|
+
handle_selected_jobs jobs
|
74
82
|
rescue ::ArgumentError
|
75
83
|
bad_request
|
76
84
|
end
|
77
85
|
|
78
|
-
def
|
86
|
+
def handle_selected_jobs(jobs)
|
87
|
+
return send_data(*prepare_data(jobs.map(&:item), EXPORT_CHUNK_SIZE)) if parsed_params["export"]
|
88
|
+
|
89
|
+
if parsed_params["retry"]
|
90
|
+
jobs.each(&:retry)
|
91
|
+
elsif parsed_params["delete"]
|
92
|
+
jobs.each(&:delete)
|
93
|
+
end
|
94
|
+
|
95
|
+
redirect redirect_path(request)
|
96
|
+
end
|
97
|
+
|
98
|
+
def post_undertaker_job_class_error_class_error_msg_bucket_name_delete
|
79
99
|
store_request_params
|
80
|
-
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(
|
100
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
81
101
|
@dead_jobs.each do |dead_job|
|
82
102
|
dead_job.job.delete
|
83
103
|
end
|
@@ -85,10 +105,10 @@ module Sidekiq
|
|
85
105
|
redirect redirect_path(request)
|
86
106
|
end
|
87
107
|
|
88
|
-
def
|
108
|
+
def post_undertaker_job_class_error_class_error_msg_bucket_name_retry
|
89
109
|
store_request_params
|
90
110
|
|
91
|
-
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(
|
111
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
92
112
|
@dead_jobs.each do |dead_job|
|
93
113
|
dead_job.job.retry
|
94
114
|
end
|
@@ -96,14 +116,45 @@ module Sidekiq
|
|
96
116
|
redirect redirect_path(request)
|
97
117
|
end
|
98
118
|
|
119
|
+
def post_undertaker_job_class_error_class_error_msg_bucket_name_export
|
120
|
+
store_request_params
|
121
|
+
|
122
|
+
@dead_jobs = Sidekiq::Undertaker::JobFilter.filter_dead_jobs(parsed_params)
|
123
|
+
send_data(*prepare_data(@dead_jobs.map { |j| j.job.item }, EXPORT_CHUNK_SIZE))
|
124
|
+
end
|
125
|
+
|
126
|
+
def post_import_jobs
|
127
|
+
file = parsed_params["upload_file"]
|
128
|
+
raise ::ArgumentError.new("The file is not a json") if file.nil? || file[:type] != "application/json"
|
129
|
+
|
130
|
+
data = parsed_params["upload_file"][:tempfile].read
|
131
|
+
dead_set = Sidekiq::DeadSet.new
|
132
|
+
|
133
|
+
JSON.parse(data).each do |job|
|
134
|
+
dead_set.kill(Sidekiq.dump_json(job))
|
135
|
+
end
|
136
|
+
redirect redirect_path(request)
|
137
|
+
rescue StandardError
|
138
|
+
bad_request
|
139
|
+
end
|
140
|
+
|
99
141
|
def render_result(template)
|
100
142
|
render(:erb, File.read(File.join(view_path, template)))
|
101
143
|
end
|
102
144
|
|
103
145
|
def store_request_params
|
104
|
-
@req_job_class =
|
105
|
-
@req_bucket_name =
|
106
|
-
@req_error_class =
|
146
|
+
@req_job_class = parsed_params["job_class"]
|
147
|
+
@req_bucket_name = parsed_params["bucket_name"]
|
148
|
+
@req_error_class = parsed_params["error_class"]
|
149
|
+
@req_error_msg = parsed_params["error_msg"]
|
150
|
+
end
|
151
|
+
|
152
|
+
def parsed_params
|
153
|
+
@parsed_params ||= if params["error_msg"] && params["error_msg"] != "all"
|
154
|
+
params.merge("error_msg" => Base64.urlsafe_decode64(params["error_msg"]))
|
155
|
+
else
|
156
|
+
params
|
157
|
+
end
|
107
158
|
end
|
108
159
|
|
109
160
|
def view_path
|
@@ -112,13 +163,40 @@ module Sidekiq
|
|
112
163
|
|
113
164
|
def redirect_path(request)
|
114
165
|
path = request.referer ? URI.parse(request.referer).path : request.path
|
115
|
-
path.gsub("/delete", "").gsub("/retry", "")
|
166
|
+
path.gsub("/delete", "").gsub("/retry", "").gsub("/export", "")
|
167
|
+
end
|
168
|
+
|
169
|
+
def prepare_data(data, chunk_size)
|
170
|
+
filename = Time.now.strftime("%Y-%m-%d_%H-%M").to_s
|
171
|
+
return [data.to_json, "application/json", "#{filename}.json"] if data.length <= chunk_size
|
172
|
+
|
173
|
+
filename = "#{@req_job_class}_#{filename}"
|
174
|
+
zip = Zip::OutputStream.write_buffer do |file|
|
175
|
+
data.each_slice(chunk_size).each_with_index do |chunk, index|
|
176
|
+
file.put_next_entry("#{filename}_part-#{index + 1}.json")
|
177
|
+
file.write chunk.to_json
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
[zip.string, "application/zip", "#{filename}.zip"]
|
182
|
+
end
|
183
|
+
|
184
|
+
def send_data(data, content_type = "text/plain", file_name = "attachment.txt")
|
185
|
+
[
|
186
|
+
200,
|
187
|
+
{
|
188
|
+
"Content-Type" => content_type,
|
189
|
+
"Content-Disposition" => "attachment; filename=\"#{file_name}\""
|
190
|
+
},
|
191
|
+
[data]
|
192
|
+
]
|
116
193
|
end
|
117
194
|
|
118
195
|
def bad_request
|
119
196
|
[400, { "Content-Type" => "text/plain" }, ["Bad Request"]]
|
120
197
|
end
|
121
198
|
end
|
199
|
+
# rubocop:enable Metrics/ModuleLength
|
122
200
|
end
|
123
201
|
end
|
124
202
|
end
|
@@ -12,25 +12,34 @@ module Sidekiq
|
|
12
12
|
app.get "/undertaker/filter" do
|
13
13
|
show_filter
|
14
14
|
end
|
15
|
-
|
16
15
|
app.get "/undertaker/filter/:job_class/:bucket_name" do
|
17
16
|
show_filter_by_job_class_bucket_name
|
18
17
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
app.get "/undertaker/filter/:job_class/:error_class/:bucket_name" do
|
19
|
+
show_filter_by_job_class_error_class_bucket_name
|
20
|
+
end
|
21
|
+
app.get "/undertaker/morgue/:job_class/:error_class/:error_msg/:bucket_name" do
|
22
|
+
show_undertaker_by_job_class_error_class_error_msg_bucket_name
|
22
23
|
end
|
23
24
|
|
24
25
|
app.post "/undertaker/morgue" do
|
25
26
|
post_undertaker
|
26
27
|
end
|
27
28
|
|
28
|
-
app.post "/undertaker/morgue/:job_class/:error_class/:bucket_name/delete" do
|
29
|
-
|
29
|
+
app.post "/undertaker/morgue/:job_class/:error_class/:error_msg/:bucket_name/delete" do
|
30
|
+
post_undertaker_job_class_error_class_error_msg_bucket_name_delete
|
31
|
+
end
|
32
|
+
|
33
|
+
app.post "/undertaker/morgue/:job_class/:error_class/:error_msg/:bucket_name/retry" do
|
34
|
+
post_undertaker_job_class_error_class_error_msg_bucket_name_retry
|
35
|
+
end
|
36
|
+
|
37
|
+
app.post "/undertaker/morgue/:job_class/:error_class/:error_msg/:bucket_name/export" do
|
38
|
+
post_undertaker_job_class_error_class_error_msg_bucket_name_export
|
30
39
|
end
|
31
40
|
|
32
|
-
app.post "/undertaker/
|
33
|
-
|
41
|
+
app.post "/undertaker/import_jobs" do
|
42
|
+
post_import_jobs
|
34
43
|
end
|
35
44
|
end
|
36
45
|
# rubocop:enable Metrics/MethodLength
|
data/sidekiq-undertaker.gemspec
CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.metadata = {
|
22
22
|
"homepage_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker",
|
23
23
|
"source_code_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker",
|
24
|
+
"changelog_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker/blob/master/CHANGELOG.md",
|
24
25
|
"bug_tracker_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker/issues",
|
25
|
-
"build_status_uri" => "https://
|
26
|
+
"build_status_uri" => "https://github.com/ThomasKoppensteiner/sidekiq-undertaker/actions/workflows/ruby-build.yml",
|
26
27
|
"rubygems_mfa_required" => "true"
|
27
28
|
}
|
28
29
|
|
@@ -30,7 +31,6 @@ Gem::Specification.new do |spec|
|
|
30
31
|
|
31
32
|
spec.files = `git ls-files -z`.split("\x0")
|
32
33
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
33
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
34
34
|
spec.require_paths = ["lib", "lib/sidekiq/undertaker"]
|
35
35
|
|
36
36
|
spec.add_development_dependency "bundler", ">= 1.17", "<3"
|
@@ -46,13 +46,14 @@ Gem::Specification.new do |spec|
|
|
46
46
|
spec.add_development_dependency "rspec-mocks", "~> 3.8"
|
47
47
|
spec.add_development_dependency "rspec-sidekiq", "~> 3.0"
|
48
48
|
spec.add_development_dependency "rt_rubocop_defaults", "~> 2.3"
|
49
|
-
spec.add_development_dependency "rubocop", "~> 1.
|
49
|
+
spec.add_development_dependency "rubocop", "~> 1.30"
|
50
50
|
spec.add_development_dependency "rubocop-rake", "~> 0.5"
|
51
51
|
spec.add_development_dependency "rubocop-rspec", "~> 2.0"
|
52
52
|
spec.add_development_dependency "rubocop_runner", "~> 2.1"
|
53
|
-
spec.add_development_dependency "simplecov", "~> 0.
|
53
|
+
spec.add_development_dependency "simplecov", "~> 0.21"
|
54
54
|
spec.add_development_dependency "sinatra", "~> 2.0"
|
55
55
|
spec.add_development_dependency "timecop", "~> 0.9"
|
56
56
|
|
57
|
-
spec.add_runtime_dependency "
|
57
|
+
spec.add_runtime_dependency "rubyzip", "~> 2.3"
|
58
|
+
spec.add_runtime_dependency "sidekiq", ">= 6.4", "< 7"
|
58
59
|
end
|