sidekiq-undertaker 1.1.1 → 1.4.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-build.yml +31 -3
  3. data/.rubocop.yml +4 -0
  4. data/.rubocop_codeclimate.yml +9 -0
  5. data/CHANGELOG.md +19 -0
  6. data/README.md +8 -6
  7. data/assets/Undertaker_demo_1_job_1_error.png +0 -0
  8. data/assets/Undertaker_demo_1_job_all_errors.png +0 -0
  9. data/assets/Undertaker_demo_all_errors.png +0 -0
  10. data/assets/Undertaker_demo_all_jobs.png +0 -0
  11. data/assets/Undertaker_demo_all_jobs_1_error.png +0 -0
  12. data/lib/sidekiq/undertaker/dead_job.rb +10 -2
  13. data/lib/sidekiq/undertaker/job_distributor.rb +4 -0
  14. data/lib/sidekiq/undertaker/job_filter.rb +7 -2
  15. data/lib/sidekiq/undertaker/version.rb +1 -1
  16. data/lib/sidekiq/undertaker/web_extension/api_helpers.rb +104 -26
  17. data/lib/sidekiq/undertaker/web_extension.rb +17 -8
  18. data/sidekiq-undertaker.gemspec +6 -5
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. data/spec/sidekiq/undertaker/dead_jobs_spec.rb +7 -4
  30. data/spec/sidekiq/undertaker/job_distributor_spec.rb +41 -19
  31. data/spec/sidekiq/undertaker/job_filter_spec.rb +26 -9
  32. data/spec/sidekiq/undertaker/web_extension_spec.rb +172 -14
  33. data/spec/spec_helper.rb +4 -0
  34. data/web/locales/en.yml +2 -0
  35. data/web/views/filter.erb +17 -1
  36. data/web/views/filter_job_class.erb +8 -8
  37. data/web/views/filter_job_class_error_class.erb +36 -0
  38. data/web/views/morgue.erb +9 -2
  39. metadata +38 -30
  40. data/.travis.yml +0 -51
  41. data/Demo_Filter.png +0 -0
  42. data/Demo_Job_Filter.png +0 -0
  43. data/Demo_Morgue_1_Job.png +0 -0
  44. data/Demo_Morgue_all.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00e0e140904b2a6c034ae86443f4097405c27089bd402faa9c567b9a4ed494ac
4
- data.tar.gz: df53ecae31dbf8ab6535016bee735ab199eec205251e54332bd7e1f221c584f5
3
+ metadata.gz: c9faade9f819fcaff3bc2246d68197d085f6f90b10b82f38290f5a3cc5752f07
4
+ data.tar.gz: c08b3349474057a180eecf4cc64b0bb15f43112b264833bc6f9441b5ee139549
5
5
  SHA512:
6
- metadata.gz: c91f3a2c28ac45514a4b2de47bfbbb9029bf1377daf88ae7aa589f807fb59e6d691fc717f6661041966561d76eb516de80e7cf52a9e8bb78a6c7ac8556b9ac5b
7
- data.tar.gz: 57177fcdb514ab963e3b67917938b8571e16f0209156505fd1f20cc32bf1f787f2922245406f8263f3a3d990934bb81fc445acee89329b69ade09025815d2ae7
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.0'
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@v2
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 spec
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
@@ -7,3 +7,7 @@ inherit_from: .rubocop_todo.yml
7
7
 
8
8
  AllCops:
9
9
  TargetRubyVersion: 2.5
10
+
11
+ Layout/LineLength:
12
+ Exclude:
13
+ - 'sidekiq-undertaker.gemspec'
@@ -1,5 +1,14 @@
1
1
  require:
2
+ - rubocop-rake
2
3
  - rubocop-rspec
4
+
3
5
  inherit_from:
4
6
  - .rt_rubocop_defaults.yml
5
7
  - .rubocop_todo.yml
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.5
11
+
12
+ Layout/LineLength:
13
+ Exclude:
14
+ - 'sidekiq-undertaker.gemspec'
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 Status](https://travis-ci.org/ThomasKoppensteiner/sidekiq-undertaker.svg?branch=master)](https://travis-ci.org/ThomasKoppensteiner/sidekiq-undertaker)
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](Demo_Filter.png)
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](Demo_Job_Filter.png)
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](Demo_Morgue_1_Job.png)
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](Demo_Morgue_all.png)
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
- Thank you [Zlatko Rednjak](https://github.com/Rednjak) for adding the initial version of the `CHANGELOG.md`.
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
@@ -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 &&
@@ -19,6 +19,10 @@ module Sidekiq
19
19
  group_by(:error_class)
20
20
  end
21
21
 
22
+ def group_by_error_msg
23
+ group_by(:error_msg)
24
+ end
25
+
22
26
  private
23
27
 
24
28
  def distribute
@@ -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,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Undertaker
5
- VERSION = "1.1.1"
5
+ VERSION = "1.4.0"
6
6
  end
7
7
  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(params)
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(params)
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 show_undertaker_by_job_class_error_class_bucket_name
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(params)
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 = (params[:page] || 1).to_i
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 params["key"]
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
- redirect redirect_path(request)
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 post_undertaker_job_class_error_class_buckent_name_delete
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(params)
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 post_undertaker_job_class_error_class_buckent_name_retry
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(params)
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 = params["job_class"]
105
- @req_bucket_name = params["bucket_name"]
106
- @req_error_class = params["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
- app.get "/undertaker/morgue/:job_class/:error_class/:bucket_name" do
21
- show_undertaker_by_job_class_error_class_bucket_name
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
- post_undertaker_job_class_error_class_buckent_name_delete
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/morgue/:job_class/:error_class/:bucket_name/retry" do
33
- post_undertaker_job_class_error_class_buckent_name_retry
41
+ app.post "/undertaker/import_jobs" do
42
+ post_import_jobs
34
43
  end
35
44
  end
36
45
  # rubocop:enable Metrics/MethodLength
@@ -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://travis-ci.org/ThomasKoppensteiner/sidekiq-undertaker",
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.8"
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.14"
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 "sidekiq", ">= 6.2.2", "< 6.3"
57
+ spec.add_runtime_dependency "rubyzip", "~> 2.3"
58
+ spec.add_runtime_dependency "sidekiq", ">= 6.4", "< 7"
58
59
  end