sidekiq-merger 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +10 -13
- data/Appraisals +19 -0
- data/README.md +4 -2
- data/app/Gemfile +1 -0
- data/app/Gemfile.lock +13 -1
- data/app/app.rb +32 -8
- data/app/views/index.erb +3 -1
- data/gemfiles/sidekiq_4_0.gemfile +9 -0
- data/gemfiles/sidekiq_4_1.gemfile +9 -0
- data/gemfiles/sidekiq_4_2.gemfile +9 -0
- data/gemfiles/sidekiq_5_0.gemfile +9 -0
- data/gemfiles/sidekiq_5_1.gemfile +9 -0
- data/lib/sidekiq/merger/middleware.rb +6 -4
- data/lib/sidekiq/merger/version.rb +1 -1
- data/lib/sidekiq/merger/web.rb +1 -0
- data/sidekiq-merger.gemspec +3 -2
- data/spec/sidekiq/merger/middleware_spec.rb +18 -3
- data/spec/support/worker_class.rb +15 -0
- metadata +28 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3468cfb6c6b95fa60dd5db64e5ce1a4ae04e5aac
|
4
|
+
data.tar.gz: 0b44b824a0b6ce4caf290fceae0f103c69493b9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa20b7462ba95c846352e51310eb467657a5808e5cb1d49f15801a516a34bc50e3efab585e4f940259819d1d756dedc6460811273014e8f0438ecebd6e081e64
|
7
|
+
data.tar.gz: d6d0e0b80540dbe54a1e2adc85fd4d21e4674f6370fae9db3c97b51c41da8fc02152aba089f0452599779834590f9d4087e20617d3ad5687d4e4bd84381a55e8
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,21 +1,18 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
- SIDEKIQ_VERSION=4.2.0
|
4
|
+
- 2.3.7
|
5
|
+
- 2.4.4
|
6
|
+
- 2.5.1
|
7
|
+
gemfile:
|
8
|
+
- gemfiles/sidekiq_4_0.gemfile
|
9
|
+
- gemfiles/sidekiq_4_1.gemfile
|
10
|
+
- gemfiles/sidekiq_4_2.gemfile
|
11
|
+
- gemfiles/sidekiq_5_0.gemfile
|
12
|
+
- gemfiles/sidekiq_5_1.gemfile
|
14
13
|
services:
|
15
14
|
- redis-server
|
16
|
-
|
17
|
-
- gem update --system
|
18
|
-
- gem --version
|
15
|
+
cache: bundler
|
19
16
|
script:
|
20
17
|
- "bundle exec rake spec"
|
21
18
|
- "bundle exec rubocop -D"
|
data/Appraisals
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
appraise "sidekiq-4-0" do
|
2
|
+
gem "sidekiq", "~> 4.0.0"
|
3
|
+
end
|
4
|
+
|
5
|
+
appraise "sidekiq-4-1" do
|
6
|
+
gem "sidekiq", "~> 4.1.0"
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise "sidekiq-4-2" do
|
10
|
+
gem "sidekiq", "~> 4.2.0"
|
11
|
+
end
|
12
|
+
|
13
|
+
appraise "sidekiq-5-0" do
|
14
|
+
gem "sidekiq", "~> 5.0.0"
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise "sidekiq-5-1" do
|
18
|
+
gem "sidekiq", "~> 5.1.0"
|
19
|
+
end
|
data/README.md
CHANGED
@@ -10,6 +10,8 @@
|
|
10
10
|
|
11
11
|
Merge [sidekiq](http://sidekiq.org/) jobs occurring before the execution times. Inspired by [sidekiq-grouping](https://github.com/gzigzigzeo/sidekiq-grouping).
|
12
12
|
|
13
|
+
[Demo](http://sidekiq-merger.dtaniwaki.com/)
|
14
|
+
|
13
15
|
## Use Case
|
14
16
|
|
15
17
|
### Cancel Task
|
@@ -115,13 +117,13 @@ require "sidekiq/merger/web"
|
|
115
117
|
|
116
118
|
## Test
|
117
119
|
|
118
|
-
$ bundle exec rspec
|
120
|
+
$ bundle exec appraisal rspec
|
119
121
|
|
120
122
|
The test coverage is available at `./coverage/index.html`.
|
121
123
|
|
122
124
|
## Lint
|
123
125
|
|
124
|
-
$ bundle exec rubocop
|
126
|
+
$ bundle exec appraisal rubocop
|
125
127
|
|
126
128
|
## Contributing
|
127
129
|
|
data/app/Gemfile
CHANGED
data/app/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../
|
3
3
|
specs:
|
4
|
-
sidekiq-merger (0.0.
|
4
|
+
sidekiq-merger (0.0.10)
|
5
5
|
activesupport (>= 3.2, < 6)
|
6
6
|
concurrent-ruby (~> 1.0)
|
7
7
|
sidekiq (>= 3.4, < 5)
|
@@ -14,15 +14,19 @@ GEM
|
|
14
14
|
i18n (~> 0.7)
|
15
15
|
minitest (~> 5.1)
|
16
16
|
tzinfo (~> 1.1)
|
17
|
+
backports (3.6.8)
|
17
18
|
concurrent-ruby (1.0.4)
|
18
19
|
connection_pool (2.2.1)
|
19
20
|
i18n (0.8.0)
|
20
21
|
minitest (5.10.1)
|
22
|
+
multi_json (1.12.1)
|
21
23
|
rack (1.6.5)
|
22
24
|
rack-flash3 (1.0.5)
|
23
25
|
rack
|
24
26
|
rack-protection (1.5.3)
|
25
27
|
rack
|
28
|
+
rack-test (0.6.3)
|
29
|
+
rack (>= 1.0)
|
26
30
|
redis (3.3.3)
|
27
31
|
sidekiq (4.2.9)
|
28
32
|
concurrent-ruby (~> 1.0)
|
@@ -35,6 +39,13 @@ GEM
|
|
35
39
|
rack (~> 1.5)
|
36
40
|
rack-protection (~> 1.4)
|
37
41
|
tilt (>= 1.3, < 3)
|
42
|
+
sinatra-contrib (1.4.7)
|
43
|
+
backports (>= 2.0)
|
44
|
+
multi_json
|
45
|
+
rack-protection
|
46
|
+
rack-test
|
47
|
+
sinatra (~> 1.4.0)
|
48
|
+
tilt (>= 1.3, < 3)
|
38
49
|
thread_safe (0.3.5)
|
39
50
|
tilt (2.0.6)
|
40
51
|
tzinfo (1.2.2)
|
@@ -49,6 +60,7 @@ DEPENDENCIES
|
|
49
60
|
sidekiq-merger!
|
50
61
|
sidekiq-status
|
51
62
|
sinatra
|
63
|
+
sinatra-contrib
|
52
64
|
|
53
65
|
BUNDLED WITH
|
54
66
|
1.13.6
|
data/app/app.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require_relative "./sidekiq"
|
2
2
|
require "sinatra/base"
|
3
|
+
require "sinatra/cookies"
|
4
|
+
require "securerandom"
|
3
5
|
require "rack/flash"
|
4
6
|
require "sidekiq/web"
|
5
7
|
require "sidekiq-status/web"
|
@@ -9,35 +11,57 @@ class App < Sinatra::Application
|
|
9
11
|
enable :sessions
|
10
12
|
use Rack::Flash
|
11
13
|
|
14
|
+
before do
|
15
|
+
@queue = cookies[:queue] ||= SecureRandom.urlsafe_base64(8)
|
16
|
+
end
|
17
|
+
|
12
18
|
get "/" do
|
13
19
|
erb :index
|
14
20
|
end
|
15
21
|
|
16
22
|
post "/some_worker/perform_in" do
|
17
23
|
n = rand(10)
|
18
|
-
|
19
|
-
|
24
|
+
Sidekiq::Client.push(
|
25
|
+
"queue" => @queue,
|
26
|
+
"class" => SomeWorker,
|
27
|
+
"args" => [n],
|
28
|
+
"at" => Time.now + (params[:in] || 60)
|
29
|
+
)
|
30
|
+
flash[:notice] = "Added #{n} to SomeWorker to Queue #{@queue}"
|
20
31
|
redirect "/"
|
21
32
|
end
|
22
33
|
|
23
34
|
post "/some_worker/perform_async" do
|
24
35
|
n = rand(10)
|
25
|
-
|
26
|
-
|
36
|
+
Sidekiq::Client.push(
|
37
|
+
"queue" => @queue,
|
38
|
+
"class" => SomeWorker,
|
39
|
+
"args" => [n]
|
40
|
+
)
|
41
|
+
flash[:notice] = "Added #{n} to SomeWorker to Queue #{@queue}"
|
27
42
|
redirect "/"
|
28
43
|
end
|
29
44
|
|
30
45
|
post "/unique_worker/perform_in" do
|
31
46
|
n = rand(10)
|
32
|
-
|
33
|
-
|
47
|
+
Sidekiq::Client.push(
|
48
|
+
"queue" => @queue,
|
49
|
+
"class" => UniqueWorker,
|
50
|
+
"args" => [n],
|
51
|
+
"at" => Time.now + (params[:in] || 60)
|
52
|
+
)
|
53
|
+
flash[:notice] = "Added #{n} to UniqueWorker to Queue #{@queue}"
|
34
54
|
redirect "/"
|
35
55
|
end
|
36
56
|
|
37
57
|
post "/unique_worker/perform_async" do
|
38
58
|
n = rand(10)
|
39
|
-
|
40
|
-
|
59
|
+
Sidekiq::Client.push(
|
60
|
+
"queue" => @queue,
|
61
|
+
"class" => UniqueWorker,
|
62
|
+
"args" => [n]
|
63
|
+
)
|
64
|
+
flash[:notice] = "Added #{n} to UniqueWorker to Queue #{@queue}"
|
41
65
|
redirect "/"
|
42
66
|
end
|
43
67
|
end
|
data/app/views/index.erb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
<head>
|
4
4
|
<meta charset="UTF-8">
|
5
5
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
6
|
+
<title>Sidekiq Merger</title>
|
7
|
+
<meta name="description" content="Merge sidekiq jobs occurring before the execution times. Inspired by sidekiq-grouping.">
|
6
8
|
</head>
|
7
9
|
<body>
|
8
10
|
<header class="navbar">
|
@@ -21,7 +23,7 @@
|
|
21
23
|
<p class="lead">
|
22
24
|
Click the `perform_in` buttons to create or merge tasks until the execution time (in 60s).<br>
|
23
25
|
Click the `perform_async` buttons to execute a single task.<br><br>
|
24
|
-
Open <a href="/sidekiq/merges?
|
26
|
+
Open <a href="<%= "/sidekiq/merges?queue=#{@queue}" %>" target="_blank">sidekiq console</a> to check what happens.
|
25
27
|
</p>
|
26
28
|
<div>
|
27
29
|
<h2>SomeWorker</h2>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative "merge"
|
2
2
|
|
3
3
|
class Sidekiq::Merger::Middleware
|
4
|
-
def call(worker_class, msg, queue,
|
4
|
+
def call(worker_class, msg, queue, _ = nil)
|
5
5
|
return yield if defined?(Sidekiq::Testing) && Sidekiq::Testing.inline?
|
6
6
|
|
7
7
|
worker_class = worker_class.camelize.constantize if worker_class.is_a?(String)
|
@@ -9,14 +9,16 @@ class Sidekiq::Merger::Middleware
|
|
9
9
|
|
10
10
|
merger_enabled = options.key?("merger")
|
11
11
|
|
12
|
-
|
12
|
+
return yield unless merger_enabled
|
13
|
+
|
14
|
+
if !msg["at"].nil? && msg["at"].to_f > Time.now.to_f
|
13
15
|
Sidekiq::Merger::Merge
|
14
16
|
.initialize_with_args(worker_class, queue, msg["args"])
|
15
17
|
.add(msg["args"], msg["at"])
|
16
18
|
false
|
17
19
|
else
|
18
|
-
msg["args"] = [msg["args"]] unless msg.delete("merged")
|
19
|
-
yield
|
20
|
+
msg["args"] = [msg["args"].flatten] unless msg.delete("merged")
|
21
|
+
yield
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
data/lib/sidekiq/merger/web.rb
CHANGED
@@ -6,6 +6,7 @@ module Sidekiq::Merger::Web
|
|
6
6
|
def self.registered(app)
|
7
7
|
app.get "/merges" do
|
8
8
|
@merges = Sidekiq::Merger::Merge.all
|
9
|
+
@merges.select! { |m| m.queue == params[:queue] } unless params[:queue].nil?
|
9
10
|
erb File.read(File.join(VIEWS, "index.erb")), locals: { view_path: VIEWS }
|
10
11
|
end
|
11
12
|
|
data/sidekiq-merger.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.required_ruby_version = [">= 2.2.2", "< 2.
|
25
|
+
spec.required_ruby_version = [">= 2.2.2", "< 2.6"]
|
26
26
|
|
27
27
|
spec.add_development_dependency "rake", ">= 10.0", "< 13"
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.0", "< 4"
|
@@ -30,8 +30,9 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "timecop", "~> 0.8"
|
31
31
|
spec.add_development_dependency "rubocop", "~> 0.47"
|
32
32
|
spec.add_development_dependency "coveralls", "~> 0.8"
|
33
|
+
spec.add_development_dependency "appraisal"
|
33
34
|
|
34
|
-
spec.add_runtime_dependency "sidekiq", ">=
|
35
|
+
spec.add_runtime_dependency "sidekiq", ">= 4.0", "< 6"
|
35
36
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
36
37
|
spec.add_runtime_dependency "activesupport", ">= 3.2", "< 6"
|
37
38
|
end
|
@@ -10,6 +10,15 @@ describe Sidekiq::Merger::Middleware, worker_class: true do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe "#call" do
|
13
|
+
context "non-merger worker" do
|
14
|
+
it "leaves args alone" do
|
15
|
+
msg = { "args" => [1, 2, 3] }
|
16
|
+
expect { |b| subject.call(non_merge_worker_class, msg, queue, &b) }.to yield_with_no_args
|
17
|
+
expect(msg).to eq({ "args" => [1, 2, 3] }) #unmodified
|
18
|
+
flusher.flush
|
19
|
+
expect(worker_class.jobs.size).to eq 0
|
20
|
+
end
|
21
|
+
end
|
13
22
|
it "adds the args to the merge" do
|
14
23
|
subject.call(worker_class, { "args" => [1, 2, 3], "at" => (now + 10.seconds).to_f }, queue) {}
|
15
24
|
subject.call(worker_class, { "args" => [2, 3, 4], "at" => (now + 15.seconds).to_f }, queue) {}
|
@@ -24,13 +33,17 @@ describe Sidekiq::Merger::Middleware, worker_class: true do
|
|
24
33
|
end
|
25
34
|
context "without at msg" do
|
26
35
|
it "peforms now with brackets" do
|
27
|
-
|
36
|
+
msg = { "args" => [1, 2, 3] }
|
37
|
+
expect { |b| subject.call(worker_class, msg, queue, &b) }.to yield_with_no_args
|
38
|
+
expect(msg).to eq({ "args" => [[1, 2, 3]] })
|
28
39
|
flusher.flush
|
29
40
|
expect(worker_class.jobs.size).to eq 0
|
30
41
|
end
|
31
42
|
context "merged msgs" do
|
32
43
|
it "performs now" do
|
33
|
-
|
44
|
+
msg = { "args" => [[1, 2, 3]], "merged" => true }
|
45
|
+
expect { |b| subject.call(worker_class, msg, queue, &b) }.to yield_with_no_args
|
46
|
+
expect(msg).to eq({ "args" => [[1, 2, 3]] })
|
34
47
|
flusher.flush
|
35
48
|
expect(worker_class.jobs.size).to eq 0
|
36
49
|
end
|
@@ -38,7 +51,9 @@ describe Sidekiq::Merger::Middleware, worker_class: true do
|
|
38
51
|
end
|
39
52
|
context "at is before current time" do
|
40
53
|
it "peforms now" do
|
41
|
-
|
54
|
+
msg = { "args" => [1, 2, 3], "at" => now.to_f }
|
55
|
+
expect { |b| subject.call(worker_class, msg, queue, &b) }.to yield_with_no_args
|
56
|
+
expect(msg).to eq({ "args" => [[1, 2, 3]], "at" => now.to_f })
|
42
57
|
flusher.flush
|
43
58
|
expect(worker_class.jobs.size).to eq 0
|
44
59
|
end
|
@@ -19,16 +19,31 @@ RSpec.shared_context "worker class", worker_class: true do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
+
let(:non_merge_worker_class) do
|
23
|
+
Class.new do
|
24
|
+
include Sidekiq::Worker
|
25
|
+
|
26
|
+
def self.to_s
|
27
|
+
"NonMergeWorker"
|
28
|
+
end
|
29
|
+
|
30
|
+
def perform(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
22
34
|
before :example do
|
23
35
|
allow(Object).to receive(:const_get).with(anything).and_call_original
|
24
36
|
allow(Object).to receive(:const_get).with("SomeWorker").and_return worker_class
|
37
|
+
allow(Object).to receive(:const_get).with("NonMergeWorker").and_return non_merge_worker_class
|
25
38
|
end
|
26
39
|
around :example do |example|
|
27
40
|
worker_class.jobs.clear
|
41
|
+
non_merge_worker_class.jobs.clear
|
28
42
|
begin
|
29
43
|
example.run
|
30
44
|
ensure
|
31
45
|
worker_class.jobs.clear
|
46
|
+
non_merge_worker_class.jobs.clear
|
32
47
|
end
|
33
48
|
end
|
34
49
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-merger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dtaniwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -106,26 +106,40 @@ dependencies:
|
|
106
106
|
- - "~>"
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0.8'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: appraisal
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
109
123
|
- !ruby/object:Gem::Dependency
|
110
124
|
name: sidekiq
|
111
125
|
requirement: !ruby/object:Gem::Requirement
|
112
126
|
requirements:
|
113
127
|
- - ">="
|
114
128
|
- !ruby/object:Gem::Version
|
115
|
-
version: '
|
129
|
+
version: '4.0'
|
116
130
|
- - "<"
|
117
131
|
- !ruby/object:Gem::Version
|
118
|
-
version: '
|
132
|
+
version: '6'
|
119
133
|
type: :runtime
|
120
134
|
prerelease: false
|
121
135
|
version_requirements: !ruby/object:Gem::Requirement
|
122
136
|
requirements:
|
123
137
|
- - ">="
|
124
138
|
- !ruby/object:Gem::Version
|
125
|
-
version: '
|
139
|
+
version: '4.0'
|
126
140
|
- - "<"
|
127
141
|
- !ruby/object:Gem::Version
|
128
|
-
version: '
|
142
|
+
version: '6'
|
129
143
|
- !ruby/object:Gem::Dependency
|
130
144
|
name: concurrent-ruby
|
131
145
|
requirement: !ruby/object:Gem::Requirement
|
@@ -174,6 +188,7 @@ files:
|
|
174
188
|
- ".rspec"
|
175
189
|
- ".rubocop.yml"
|
176
190
|
- ".travis.yml"
|
191
|
+
- Appraisals
|
177
192
|
- Dockerfile
|
178
193
|
- Gemfile
|
179
194
|
- LICENSE
|
@@ -189,6 +204,11 @@ files:
|
|
189
204
|
- app/workers/unique_worker.rb
|
190
205
|
- docker-compose-common.yml
|
191
206
|
- docker-compose.yml
|
207
|
+
- gemfiles/sidekiq_4_0.gemfile
|
208
|
+
- gemfiles/sidekiq_4_1.gemfile
|
209
|
+
- gemfiles/sidekiq_4_2.gemfile
|
210
|
+
- gemfiles/sidekiq_5_0.gemfile
|
211
|
+
- gemfiles/sidekiq_5_1.gemfile
|
192
212
|
- lib/sidekiq-merger.rb
|
193
213
|
- lib/sidekiq/merger.rb
|
194
214
|
- lib/sidekiq/merger/config.rb
|
@@ -228,7 +248,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
228
248
|
version: 2.2.2
|
229
249
|
- - "<"
|
230
250
|
- !ruby/object:Gem::Version
|
231
|
-
version: '2.
|
251
|
+
version: '2.6'
|
232
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
233
253
|
requirements:
|
234
254
|
- - ">="
|
@@ -236,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
236
256
|
version: '0'
|
237
257
|
requirements: []
|
238
258
|
rubyforge_project:
|
239
|
-
rubygems_version: 2.
|
259
|
+
rubygems_version: 2.6.8
|
240
260
|
signing_key:
|
241
261
|
specification_version: 4
|
242
262
|
summary: Sidekiq merger plugin
|