sidekiq-merger 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +21 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +18 -16
- data/.travis.yml +12 -6
- data/Appraisals +19 -0
- data/Dockerfile +5 -2
- data/Gemfile +2 -0
- data/README.md +26 -3
- data/app/Gemfile +1 -0
- data/app/Gemfile.lock +14 -2
- data/app/app.rb +32 -8
- data/app/views/index.erb +55 -26
- data/docker-compose.yml +2 -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/config.rb +1 -1
- data/lib/sidekiq/merger/merge.rb +10 -6
- data/lib/sidekiq/merger/middleware.rb +6 -4
- data/lib/sidekiq/merger/version.rb +1 -1
- data/lib/sidekiq/merger/views/index.erb +1 -1
- data/lib/sidekiq/merger/web.rb +1 -0
- data/lib/sidekiq/merger.rb +8 -0
- data/misc/bulk_notification_flow.png +0 -0
- data/misc/cancel_task_flow.png +0 -0
- data/sidekiq-merger.gemspec +4 -3
- data/spec/sidekiq/merger/merge_spec.rb +52 -38
- data/spec/sidekiq/merger/middleware_spec.rb +19 -21
- data/spec/sidekiq/merger_spec.rb +16 -1
- data/spec/spec_helper.rb +9 -19
- data/spec/support/worker_class.rb +49 -0
- metadata +38 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 53e070ac5acbed069e9ac6b49e9f43651bdf0e061a8a29d461e5b40111c8c5f7
|
4
|
+
data.tar.gz: 9d08abf9726549e6dacb30a6382591bcb7d86b3bf219c30b4c151b471346872e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8baeb68048097d0e32c31ebb099f658fdb7201bccd8fed439956a60d82fd309d67dec63d4bfd95c4276c72d115c669d8fc49bf0405de789d28f3852725f5950c
|
7
|
+
data.tar.gz: 874696413e3d3d8b37cfa196b7adb72bb01526080017a9a34142cbd051f153568b03372d23ab36ca8944e05883452d440e88d65d20339ca3c5a35031b0402085
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
engines:
|
2
|
+
brakeman:
|
3
|
+
enabled: true
|
4
|
+
duplication:
|
5
|
+
enabled: true
|
6
|
+
config:
|
7
|
+
languages:
|
8
|
+
- ruby
|
9
|
+
fixme:
|
10
|
+
enabled: true
|
11
|
+
rubocop:
|
12
|
+
enabled: true
|
13
|
+
ratings:
|
14
|
+
paths:
|
15
|
+
- Gemfile.lock
|
16
|
+
- "**.erb"
|
17
|
+
- "**.rb"
|
18
|
+
exclude_paths:
|
19
|
+
- "app/"
|
20
|
+
- "spec/"
|
21
|
+
- "misc/"
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
AllCops:
|
2
2
|
DisabledByDefault: true
|
3
|
+
Exclude:
|
4
|
+
- 'gemfiles/**/*'
|
3
5
|
|
4
6
|
Style/StringLiterals:
|
5
7
|
Enabled: true
|
@@ -9,39 +11,42 @@ Style/StringLiteralsInInterpolation:
|
|
9
11
|
Enabled: true
|
10
12
|
EnforcedStyle: double_quotes
|
11
13
|
|
12
|
-
|
14
|
+
Layout/SpaceBeforeBlockBraces:
|
13
15
|
Enabled: true
|
14
16
|
EnforcedStyle: 'space'
|
15
17
|
|
16
|
-
|
18
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
19
|
+
Enabled: true
|
20
|
+
|
21
|
+
Layout/SpaceInsideReferenceBrackets:
|
17
22
|
Enabled: true
|
18
23
|
|
19
|
-
|
24
|
+
Layout/SpaceInsideHashLiteralBraces:
|
20
25
|
Enabled: true
|
21
26
|
|
22
|
-
|
27
|
+
Layout/SpaceInsideBlockBraces:
|
23
28
|
Enabled: true
|
24
29
|
|
25
|
-
|
30
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
26
31
|
Enabled: true
|
27
32
|
|
28
|
-
|
33
|
+
Layout/SpaceBeforeComma:
|
29
34
|
Enabled: false
|
30
35
|
|
31
|
-
|
36
|
+
Layout/SpaceAroundOperators:
|
32
37
|
Enabled: true
|
33
38
|
|
34
|
-
|
39
|
+
Layout/SpaceAfterComma:
|
35
40
|
Enabled: true
|
36
41
|
|
37
|
-
|
42
|
+
Layout/ExtraSpacing:
|
38
43
|
Enabled: true
|
39
44
|
AllowForAlignment: true
|
40
45
|
|
41
46
|
Lint/DuplicateMethods:
|
42
47
|
Enabled: true
|
43
48
|
|
44
|
-
|
49
|
+
Layout/LineLength:
|
45
50
|
Enabled: true
|
46
51
|
Max: 200
|
47
52
|
AllowHeredoc: true
|
@@ -65,16 +70,13 @@ Style/ClassAndModuleChildren:
|
|
65
70
|
Exclude:
|
66
71
|
- lib/sidekiq/merger/version.rb
|
67
72
|
|
68
|
-
|
69
|
-
Enabled: true
|
70
|
-
|
71
|
-
Style/AlignArray:
|
73
|
+
Layout/ArrayAlignment:
|
72
74
|
Enabled: true
|
73
75
|
|
74
|
-
|
76
|
+
Layout/HashAlignment:
|
75
77
|
Enabled: true
|
76
78
|
|
77
|
-
|
79
|
+
Layout/BlockEndNewline:
|
78
80
|
Enabled: false
|
79
81
|
|
80
82
|
Style/DoubleNegation:
|
data/.travis.yml
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
- 2.
|
4
|
+
- 2.5.9
|
5
|
+
- 2.6.7
|
6
|
+
- 2.7.3
|
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
|
7
13
|
services:
|
8
14
|
- redis-server
|
9
|
-
|
10
|
-
- gem update --system
|
11
|
-
- gem --version
|
15
|
+
cache: bundler
|
12
16
|
script:
|
13
17
|
- "bundle exec rake spec"
|
14
18
|
- "bundle exec rubocop -D"
|
19
|
+
notifications:
|
20
|
+
email: false
|
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/Dockerfile
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
FROM ruby:2.3.3
|
2
2
|
MAINTAINER dtaniwaki
|
3
3
|
|
4
|
-
ENV PORT
|
4
|
+
ENV PORT 3000
|
5
|
+
ENV REDIS_HOST 127.0.0.1
|
6
|
+
ENV REDIS_PORT 6379
|
7
|
+
|
5
8
|
RUN gem install bundler
|
6
9
|
ADD . /gem
|
7
10
|
WORKDIR /gem/app
|
8
11
|
RUN bundle install -j4
|
9
12
|
|
10
|
-
EXPOSE
|
13
|
+
EXPOSE $PORT
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -6,8 +6,22 @@
|
|
6
6
|
[![Coverage Status][cov-image]][cov-link]
|
7
7
|
[![Code Climate][gpa-image]][gpa-link]
|
8
8
|
|
9
|
+
[![Docker][docker-hub-image]][docker-hub-link]
|
10
|
+
|
9
11
|
Merge [sidekiq](http://sidekiq.org/) jobs occurring before the execution times. Inspired by [sidekiq-grouping](https://github.com/gzigzigzeo/sidekiq-grouping).
|
10
12
|
|
13
|
+
[Demo](http://sidekiq-merger.dtaniwaki.com/)
|
14
|
+
|
15
|
+
## Use Case
|
16
|
+
|
17
|
+
### Cancel Task
|
18
|
+
|
19
|
+
![Cancel Task](misc/cancel_task_flow.png)
|
20
|
+
|
21
|
+
### Bulk Notification
|
22
|
+
|
23
|
+
![Bulk Notification](misc/bulk_notification_flow.png)
|
24
|
+
|
11
25
|
## Installation
|
12
26
|
|
13
27
|
Add this line to your application's Gemfile:
|
@@ -91,6 +105,14 @@ Format: `Boolean`
|
|
91
105
|
|
92
106
|
e.g. `true`
|
93
107
|
|
108
|
+
### `batch_size` (optional, default: `nil`)
|
109
|
+
|
110
|
+
Allow to specify how many jobs max to provide as arguments per aggregation
|
111
|
+
|
112
|
+
Format: `Int`
|
113
|
+
|
114
|
+
e.g. `50`
|
115
|
+
|
94
116
|
## Web UI
|
95
117
|
|
96
118
|
![Web UI](misc/web_ui.png)
|
@@ -103,13 +125,13 @@ require "sidekiq/merger/web"
|
|
103
125
|
|
104
126
|
## Test
|
105
127
|
|
106
|
-
$ bundle exec rspec
|
128
|
+
$ bundle exec appraisal rspec
|
107
129
|
|
108
130
|
The test coverage is available at `./coverage/index.html`.
|
109
131
|
|
110
132
|
## Lint
|
111
133
|
|
112
|
-
$ bundle exec rubocop
|
134
|
+
$ bundle exec appraisal rubocop
|
113
135
|
|
114
136
|
## Contributing
|
115
137
|
|
@@ -133,4 +155,5 @@ Copyright (c) 2017 dtaniwaki. See [LICENSE](LICENSE) for details.
|
|
133
155
|
[cov-link]: https://coveralls.io/r/dtaniwaki/sidekiq-merger
|
134
156
|
[gpa-image]: https://codeclimate.com/github/dtaniwaki/sidekiq-merger.svg
|
135
157
|
[gpa-link]: https://codeclimate.com/github/dtaniwaki/sidekiq-merger
|
136
|
-
|
158
|
+
[docker-hub-image]: http://dockeri.co/image/dtaniwaki/sidekiq-merger
|
159
|
+
[docker-hub-link]: https://hub.docker.com/r/dtaniwaki/sidekiq-merger/
|
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
|
-
i18n (0.
|
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
@@ -1,35 +1,64 @@
|
|
1
|
-
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
2
3
|
<head>
|
3
|
-
<meta charset="UTF-8">
|
4
|
+
<meta charset="UTF-8">
|
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.">
|
4
8
|
</head>
|
5
9
|
<body>
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
<p>
|
11
|
-
<a href="/sidekiq" target="_blank">Open sidekiq console</a>
|
12
|
-
</p>
|
13
|
-
<h2>Workers</h2>
|
14
|
-
<div style="margin-left: 20px;">
|
15
|
-
<h3>SomeWorker</h3>
|
16
|
-
<div>
|
17
|
-
<form action="/some_worker/perform_in" method="post" style="display: inline-block;">
|
18
|
-
<input type="submit" name="perform_in" value="perform_in">
|
19
|
-
</form>
|
20
|
-
<form action="/some_worker/perform_in" method="post" style="display: inline-block;">
|
21
|
-
<input type="submit" name="perform_async" value="perform_async">
|
22
|
-
</form>
|
10
|
+
<header class="navbar">
|
11
|
+
<div class="container">
|
12
|
+
<h1>Sidekiq Merger</h1>
|
13
|
+
<a href="https://github.com/dtaniwaki/sidekiq-merger">View Source on GitHub →</a>
|
23
14
|
</div>
|
24
|
-
|
15
|
+
</header>
|
16
|
+
<div class="container">
|
17
|
+
<% if flash[:notice] %>
|
18
|
+
<div class="alert alert-info">
|
19
|
+
<a href="#" class="close" data-dismiss="alert">×</a>
|
20
|
+
<p><%= flash[:notice] %></p>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
23
|
+
<p class="lead">
|
24
|
+
Click the `perform_in` buttons to create or merge tasks until the execution time (in 60s).<br>
|
25
|
+
Click the `perform_async` buttons to execute a single task.<br><br>
|
26
|
+
Open <a href="<%= "/sidekiq/merges?queue=#{@queue}" %>" target="_blank">sidekiq console</a> to check what happens.
|
27
|
+
</p>
|
25
28
|
<div>
|
26
|
-
<
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
<h2>SomeWorker</h2>
|
30
|
+
<p>
|
31
|
+
<code>sidekiq_options merger: { unique: false }</code>
|
32
|
+
</p>
|
33
|
+
<p class="lead">
|
34
|
+
<small>Tasks will be merged regardless of uniqueness.</small>
|
35
|
+
</p>
|
36
|
+
<div>
|
37
|
+
<form action="/some_worker/perform_in" method="post" style="display: inline-block;">
|
38
|
+
<input type="submit" name="perform_in" value="perform_in" class="btn btn-primary">
|
39
|
+
</form>
|
40
|
+
<form action="/some_worker/perform_in" method="post" style="display: inline-block;">
|
41
|
+
<input type="submit" name="perform_async" value="perform_async" class="btn btn-default">
|
42
|
+
</form>
|
43
|
+
</div>
|
44
|
+
<h2>UniqueWorker</h2>
|
45
|
+
<p>
|
46
|
+
<code>sidekiq_options merger: { unique: true }</code>
|
47
|
+
</p>
|
48
|
+
<p class="lead">
|
49
|
+
<small>Tasks will be merged if they haven't added already.</small>
|
50
|
+
</p>
|
51
|
+
<div>
|
52
|
+
<form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
|
53
|
+
<input type="submit" name="perform_in" value="perform_in" class="btn btn-primary">
|
54
|
+
</form>
|
55
|
+
<form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
|
56
|
+
<input type="submit" name="perform_async" value="perform_async" class="btn btn-default">
|
57
|
+
</form>
|
58
|
+
</div>
|
32
59
|
</div>
|
33
60
|
</div>
|
61
|
+
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
|
62
|
+
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
34
63
|
</body>
|
35
64
|
</html>
|
data/docker-compose.yml
CHANGED
data/lib/sidekiq/merger/merge.rb
CHANGED
@@ -73,12 +73,16 @@ class Sidekiq::Merger::Merge
|
|
73
73
|
end
|
74
74
|
|
75
75
|
unless msgs.empty?
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
batches = options[:batch_size].nil? ? [msgs] : msgs.each_slice(options[:batch_size].to_i).to_a
|
77
|
+
batches.each do |batch_msgs|
|
78
|
+
# preserve FIFO when enqueuing batches
|
79
|
+
Sidekiq::Client.push(
|
80
|
+
"class" => worker_class,
|
81
|
+
"queue" => queue,
|
82
|
+
"args" => batch_msgs,
|
83
|
+
"merged" => true
|
84
|
+
)
|
85
|
+
end
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
@@ -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
|
@@ -25,7 +25,7 @@
|
|
25
25
|
<td><%= merge.all_args %></td>
|
26
26
|
<td><%= merge.execution_time || "–"%></td>
|
27
27
|
<td>
|
28
|
-
<form action="<%= "#{root_path}
|
28
|
+
<form action="<%= "#{root_path}merges/#{URI.encode_www_form_component merge.full_merge_key}/delete" %>" method="post">
|
29
29
|
<%= csrf_tag %>
|
30
30
|
<input class="btn btn-danger btn-xs" type="submit" name="delete" value="Delete" data-confirm="Are you sure you want to delete this merge?" />
|
31
31
|
</form>
|
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/lib/sidekiq/merger.rb
CHANGED
Binary file
|
Binary file
|
data/sidekiq-merger.gemspec
CHANGED
@@ -22,16 +22,17 @@ 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.
|
25
|
+
spec.required_ruby_version = [">= 2.5.0"]
|
26
26
|
|
27
27
|
spec.add_development_dependency "rake", ">= 10.0", "< 13"
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.0", "< 4"
|
29
29
|
spec.add_development_dependency "simplecov", "~> 0.12"
|
30
30
|
spec.add_development_dependency "timecop", "~> 0.8"
|
31
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
31
|
+
spec.add_development_dependency "rubocop", "~> 0.93.1"
|
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
|
@@ -1,28 +1,13 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Sidekiq::Merger::Merge do
|
3
|
+
describe Sidekiq::Merger::Merge, worker_class: true do
|
4
4
|
subject { described_class.new(worker_class, queue, args, redis: redis) }
|
5
5
|
let(:args) { "foo" }
|
6
6
|
let(:redis) { Sidekiq::Merger::Redis.new }
|
7
7
|
let(:queue) { "queue" }
|
8
8
|
let(:now) { Time.now }
|
9
9
|
let(:execution_time) { now + 10.seconds }
|
10
|
-
let(:
|
11
|
-
let(:worker_class) do
|
12
|
-
local_options = options
|
13
|
-
Class.new do
|
14
|
-
include Sidekiq::Worker
|
15
|
-
|
16
|
-
sidekiq_options merger: local_options
|
17
|
-
|
18
|
-
def self.name
|
19
|
-
"name"
|
20
|
-
end
|
21
|
-
|
22
|
-
def perform(args)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
10
|
+
let(:worker_options) { { key: -> (args) { args.to_json } } }
|
26
11
|
before { Timecop.freeze(now) }
|
27
12
|
|
28
13
|
describe ".all" do
|
@@ -64,30 +49,30 @@ describe Sidekiq::Merger::Merge do
|
|
64
49
|
|
65
50
|
describe ".merge_key" do
|
66
51
|
let(:args) { "foo" }
|
67
|
-
let(:
|
52
|
+
let(:worker_options) { {} }
|
68
53
|
it "returns an empty string" do
|
69
54
|
expect(described_class.merge_key(worker_class, args)).to eq ""
|
70
55
|
end
|
71
56
|
context "string key" do
|
72
|
-
let(:
|
57
|
+
let(:worker_options) { { key: "bar" } }
|
73
58
|
it "returns the string" do
|
74
59
|
expect(described_class.merge_key(worker_class, args)).to eq "bar"
|
75
60
|
end
|
76
61
|
end
|
77
62
|
context "other type key" do
|
78
|
-
let(:
|
63
|
+
let(:worker_options) { { key: [1, 2, 3] } }
|
79
64
|
it "returns nil" do
|
80
65
|
expect(described_class.merge_key(worker_class, args)).to eq "[1,2,3]"
|
81
66
|
end
|
82
67
|
end
|
83
68
|
context "proc key" do
|
84
69
|
let(:args) { [1, 2, 3] }
|
85
|
-
let(:
|
70
|
+
let(:worker_options) { { key: -> (args) { args[0].to_s } } }
|
86
71
|
it "returns the result of the proc" do
|
87
72
|
expect(described_class.merge_key(worker_class, args)).to eq "1"
|
88
73
|
end
|
89
74
|
context "non-string result" do
|
90
|
-
let(:
|
75
|
+
let(:worker_options) { { key: -> (args) { args[0] } } }
|
91
76
|
it "returns nil" do
|
92
77
|
expect(described_class.merge_key(worker_class, args)).to eq "1"
|
93
78
|
end
|
@@ -97,13 +82,13 @@ describe Sidekiq::Merger::Merge do
|
|
97
82
|
|
98
83
|
describe "#add" do
|
99
84
|
it "adds the args in lazy merge" do
|
100
|
-
expect(redis).to receive(:push_message).with("
|
85
|
+
expect(redis).to receive(:push_message).with("some_worker:queue:foo", [1, 2, 3], execution_time)
|
101
86
|
subject.add([1, 2, 3], execution_time)
|
102
87
|
end
|
103
88
|
context "with unique option" do
|
104
|
-
let(:
|
89
|
+
let(:worker_options) { { key: -> (args) { args.to_json }, unique: true } }
|
105
90
|
it "adds the args in lazy merge" do
|
106
|
-
expect(redis).to receive(:push_message).with("
|
91
|
+
expect(redis).to receive(:push_message).with("some_worker:queue:foo", [1, 2, 3], execution_time)
|
107
92
|
subject.add([1, 2, 3], execution_time)
|
108
93
|
end
|
109
94
|
context "the args has alredy been added" do
|
@@ -118,7 +103,7 @@ describe Sidekiq::Merger::Merge do
|
|
118
103
|
|
119
104
|
describe "#delete" do
|
120
105
|
it "adds the args in lazy merge" do
|
121
|
-
expect(redis).to receive(:delete_message).with("
|
106
|
+
expect(redis).to receive(:delete_message).with("some_worker:queue:foo", [1, 2, 3])
|
122
107
|
subject.delete([1, 2, 3])
|
123
108
|
end
|
124
109
|
end
|
@@ -156,19 +141,48 @@ describe Sidekiq::Merger::Merge do
|
|
156
141
|
end
|
157
142
|
|
158
143
|
describe "#flush" do
|
159
|
-
|
160
|
-
|
161
|
-
|
144
|
+
context "when no batch_size is configured" do
|
145
|
+
before do
|
146
|
+
subject.add([1, 2, 3], execution_time)
|
147
|
+
subject.add([2, 3, 4], execution_time)
|
148
|
+
end
|
149
|
+
it "flushes all the args" do
|
150
|
+
expect(Sidekiq::Client).to receive(:push).with(
|
151
|
+
"class" => worker_class,
|
152
|
+
"queue" => queue,
|
153
|
+
"args" => a_collection_containing_exactly([1, 2, 3], [2, 3, 4]),
|
154
|
+
"merged" => true
|
155
|
+
)
|
156
|
+
|
157
|
+
subject.flush
|
158
|
+
end
|
162
159
|
end
|
163
|
-
it "flushes all the args" do
|
164
|
-
expect(Sidekiq::Client).to receive(:push).with(
|
165
|
-
"class" => worker_class,
|
166
|
-
"queue" => queue,
|
167
|
-
"args" => a_collection_containing_exactly([1, 2, 3], [2, 3, 4]),
|
168
|
-
"merged" => true
|
169
|
-
)
|
170
160
|
|
171
|
-
|
161
|
+
context "when batch_size is configured to 2" do
|
162
|
+
let(:worker_options) { { key: -> (args) { args.to_json }, batch_size: 2 } }
|
163
|
+
before do
|
164
|
+
subject.add([1, 2, 3], execution_time)
|
165
|
+
subject.add([2, 3, 4], execution_time)
|
166
|
+
subject.add([3, 4, 5], execution_time)
|
167
|
+
subject.add([4, 5, 6], execution_time)
|
168
|
+
end
|
169
|
+
it "flushes all the args" do
|
170
|
+
expect(Sidekiq::Client).to receive(:push).with(
|
171
|
+
"class" => worker_class,
|
172
|
+
"queue" => queue,
|
173
|
+
"args" => a_collection_containing_exactly([1, 2, 3], [2, 3, 4]),
|
174
|
+
"merged" => true
|
175
|
+
)
|
176
|
+
|
177
|
+
expect(Sidekiq::Client).to receive(:push).with(
|
178
|
+
"class" => worker_class,
|
179
|
+
"queue" => queue,
|
180
|
+
"args" => a_collection_containing_exactly([3, 4, 5], [4, 5, 6]),
|
181
|
+
"merged" => true
|
182
|
+
)
|
183
|
+
|
184
|
+
subject.flush
|
185
|
+
end
|
172
186
|
end
|
173
187
|
end
|
174
188
|
|
@@ -195,7 +209,7 @@ describe Sidekiq::Merger::Merge do
|
|
195
209
|
|
196
210
|
describe "#full_merge_key" do
|
197
211
|
it "returns full merge key" do
|
198
|
-
expect(subject.full_merge_key).to eq "
|
212
|
+
expect(subject.full_merge_key).to eq "some_worker:queue:foo"
|
199
213
|
end
|
200
214
|
end
|
201
215
|
end
|
@@ -1,32 +1,24 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Sidekiq::Merger::Middleware do
|
3
|
+
describe Sidekiq::Merger::Middleware, worker_class: true do
|
4
4
|
subject { described_class.new }
|
5
5
|
let(:flusher) { Sidekiq::Merger::Flusher.new(Sidekiq.logger) }
|
6
6
|
let(:queue) { "queue" }
|
7
7
|
let(:now) { Time.now }
|
8
|
-
let(:options) { { key: -> (args) { "key" } } }
|
9
|
-
let(:worker_class) do
|
10
|
-
local_options = options
|
11
|
-
Class.new do
|
12
|
-
include Sidekiq::Worker
|
13
|
-
|
14
|
-
sidekiq_options merger: local_options
|
15
|
-
|
16
|
-
def self.name
|
17
|
-
"name"
|
18
|
-
end
|
19
|
-
|
20
|
-
def perform(*args)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
8
|
before :example do
|
25
|
-
allow(Object).to receive(:const_get).with("Name").and_return worker_class
|
26
9
|
Timecop.freeze(now)
|
27
10
|
end
|
28
11
|
|
29
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
|
30
22
|
it "adds the args to the merge" do
|
31
23
|
subject.call(worker_class, { "args" => [1, 2, 3], "at" => (now + 10.seconds).to_f }, queue) {}
|
32
24
|
subject.call(worker_class, { "args" => [2, 3, 4], "at" => (now + 15.seconds).to_f }, queue) {}
|
@@ -41,13 +33,17 @@ describe Sidekiq::Merger::Middleware do
|
|
41
33
|
end
|
42
34
|
context "without at msg" do
|
43
35
|
it "peforms now with brackets" do
|
44
|
-
|
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]] })
|
45
39
|
flusher.flush
|
46
40
|
expect(worker_class.jobs.size).to eq 0
|
47
41
|
end
|
48
42
|
context "merged msgs" do
|
49
43
|
it "performs now" do
|
50
|
-
|
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]] })
|
51
47
|
flusher.flush
|
52
48
|
expect(worker_class.jobs.size).to eq 0
|
53
49
|
end
|
@@ -55,7 +51,9 @@ describe Sidekiq::Merger::Middleware do
|
|
55
51
|
end
|
56
52
|
context "at is before current time" do
|
57
53
|
it "peforms now" do
|
58
|
-
|
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 })
|
59
57
|
flusher.flush
|
60
58
|
expect(worker_class.jobs.size).to eq 0
|
61
59
|
end
|
data/spec/sidekiq/merger_spec.rb
CHANGED
@@ -4,11 +4,26 @@ describe Sidekiq::Merger do
|
|
4
4
|
it "has a version number" do
|
5
5
|
expect(described_class::VERSION).not_to be nil
|
6
6
|
end
|
7
|
-
describe "
|
7
|
+
describe ".create_task" do
|
8
8
|
it "starts a monitoring task" do
|
9
9
|
task = described_class.create_task
|
10
10
|
expect(task).to be_a Concurrent::TimerTask
|
11
11
|
task.shutdown
|
12
12
|
end
|
13
13
|
end
|
14
|
+
describe ".configure" do
|
15
|
+
it "yields to the config" do
|
16
|
+
expect { |b| described_class.configure(&b) }.to yield_with_args(described_class.config)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
describe ".config" do
|
20
|
+
it "returns a config" do
|
21
|
+
expect(described_class.config).to be_a Sidekiq::Merger::Config
|
22
|
+
end
|
23
|
+
context "called twice" do
|
24
|
+
it "returns the same config instance" do
|
25
|
+
expect(described_class.config).to be described_class.config
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
14
29
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,31 +21,15 @@ require "sidekiq/merger"
|
|
21
21
|
Dir[File.join(__dir__, "support", "**", "*.rb")].each { |f| require f }
|
22
22
|
|
23
23
|
RSpec.configure do |config|
|
24
|
-
# rspec-expectations config goes here. You can use an alternate
|
25
|
-
# assertion/expectation library such as wrong or the stdlib/minitest
|
26
|
-
# assertions if you prefer.
|
27
24
|
config.expect_with :rspec do |expectations|
|
28
|
-
# This option will default to `true` in RSpec 4. It makes the `description`
|
29
|
-
# and `failure_message` of custom matchers include text for helper methods
|
30
|
-
# defined using `chain`, e.g.:
|
31
|
-
# be_bigger_than(2).and_smaller_than(4).description
|
32
|
-
# # => "be bigger than 2 and smaller than 4"
|
33
|
-
# ...rather than:
|
34
|
-
# # => "be bigger than 2"
|
35
25
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
36
26
|
end
|
37
27
|
|
38
28
|
config.mock_with :rspec do |mocks|
|
39
|
-
# Prevents you from mocking or stubbing a method that does not exist on
|
40
|
-
# a real object. This is generally recommended, and will default to
|
41
|
-
# `true` in RSpec 4.
|
42
29
|
mocks.verify_partial_doubles = true
|
43
30
|
end
|
44
31
|
|
45
32
|
if config.files_to_run.one?
|
46
|
-
# Use the documentation formatter for detailed output,
|
47
|
-
# unless a formatter has already been configured
|
48
|
-
# (e.g. via a command-line flag).
|
49
33
|
config.default_formatter = "doc"
|
50
34
|
end
|
51
35
|
|
@@ -57,11 +41,17 @@ RSpec.configure do |config|
|
|
57
41
|
Sidekiq::Testing.fake!
|
58
42
|
Sidekiq::Merger.logger = nil
|
59
43
|
Sidekiq.logger = nil
|
44
|
+
if Redis.respond_to?(:exists_returns_integer)
|
45
|
+
Redis.exists_returns_integer = false
|
46
|
+
end
|
60
47
|
end
|
61
48
|
|
62
|
-
config.
|
63
|
-
Sidekiq::Merger::Redis.redis
|
64
|
-
|
49
|
+
config.around :example do |example|
|
50
|
+
Sidekiq::Merger::Redis.redis { |conn| conn.flushall }
|
51
|
+
begin
|
52
|
+
example.run
|
53
|
+
ensure
|
54
|
+
Sidekiq::Merger::Redis.redis { |conn| conn.flushall }
|
65
55
|
end
|
66
56
|
end
|
67
57
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
RSpec.shared_context "worker class", worker_class: true do
|
2
|
+
let(:worker_options) { { key: -> (args) { "key" } } }
|
3
|
+
let(:worker_class) do
|
4
|
+
local_options = worker_options
|
5
|
+
Class.new do
|
6
|
+
include Sidekiq::Worker
|
7
|
+
|
8
|
+
sidekiq_options merger: local_options
|
9
|
+
|
10
|
+
def self.name
|
11
|
+
"SomeWorker"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.to_s
|
15
|
+
"SomeWorker"
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform(*args)
|
19
|
+
end
|
20
|
+
end
|
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
|
34
|
+
before :example do
|
35
|
+
allow(Object).to receive(:const_get).with(anything).and_call_original
|
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
|
38
|
+
end
|
39
|
+
around :example do |example|
|
40
|
+
worker_class.jobs.clear
|
41
|
+
non_merge_worker_class.jobs.clear
|
42
|
+
begin
|
43
|
+
example.run
|
44
|
+
ensure
|
45
|
+
worker_class.jobs.clear
|
46
|
+
non_merge_worker_class.jobs.clear
|
47
|
+
end
|
48
|
+
end
|
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.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dtaniwaki
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -84,14 +84,14 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
87
|
+
version: 0.93.1
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
94
|
+
version: 0.93.1
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: coveralls
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -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
|
@@ -167,12 +181,14 @@ executables: []
|
|
167
181
|
extensions: []
|
168
182
|
extra_rdoc_files: []
|
169
183
|
files:
|
184
|
+
- ".codeclimate.yml"
|
170
185
|
- ".dockerignore"
|
171
186
|
- ".gemrelease"
|
172
187
|
- ".gitignore"
|
173
188
|
- ".rspec"
|
174
189
|
- ".rubocop.yml"
|
175
190
|
- ".travis.yml"
|
191
|
+
- Appraisals
|
176
192
|
- Dockerfile
|
177
193
|
- Gemfile
|
178
194
|
- LICENSE
|
@@ -188,6 +204,11 @@ files:
|
|
188
204
|
- app/workers/unique_worker.rb
|
189
205
|
- docker-compose-common.yml
|
190
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
|
191
212
|
- lib/sidekiq-merger.rb
|
192
213
|
- lib/sidekiq/merger.rb
|
193
214
|
- lib/sidekiq/merger/config.rb
|
@@ -199,6 +220,8 @@ files:
|
|
199
220
|
- lib/sidekiq/merger/version.rb
|
200
221
|
- lib/sidekiq/merger/views/index.erb
|
201
222
|
- lib/sidekiq/merger/web.rb
|
223
|
+
- misc/bulk_notification_flow.png
|
224
|
+
- misc/cancel_task_flow.png
|
202
225
|
- misc/web_ui.png
|
203
226
|
- sidekiq-merger.gemspec
|
204
227
|
- spec/sidekiq/merger/flusher_spec.rb
|
@@ -209,11 +232,12 @@ files:
|
|
209
232
|
- spec/sidekiq/merger_spec.rb
|
210
233
|
- spec/spec_helper.rb
|
211
234
|
- spec/support/matchers.rb
|
235
|
+
- spec/support/worker_class.rb
|
212
236
|
homepage: https://github.com/dtaniwaki/sidekiq-merger
|
213
237
|
licenses:
|
214
238
|
- MIT
|
215
239
|
metadata: {}
|
216
|
-
post_install_message:
|
240
|
+
post_install_message:
|
217
241
|
rdoc_options: []
|
218
242
|
require_paths:
|
219
243
|
- lib
|
@@ -221,19 +245,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
221
245
|
requirements:
|
222
246
|
- - ">="
|
223
247
|
- !ruby/object:Gem::Version
|
224
|
-
version: 2.
|
225
|
-
- - "<"
|
226
|
-
- !ruby/object:Gem::Version
|
227
|
-
version: '2.5'
|
248
|
+
version: 2.5.0
|
228
249
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
229
250
|
requirements:
|
230
251
|
- - ">="
|
231
252
|
- !ruby/object:Gem::Version
|
232
253
|
version: '0'
|
233
254
|
requirements: []
|
234
|
-
|
235
|
-
|
236
|
-
signing_key:
|
255
|
+
rubygems_version: 3.1.2
|
256
|
+
signing_key:
|
237
257
|
specification_version: 4
|
238
258
|
summary: Sidekiq merger plugin
|
239
259
|
test_files:
|
@@ -245,3 +265,4 @@ test_files:
|
|
245
265
|
- spec/sidekiq/merger_spec.rb
|
246
266
|
- spec/spec_helper.rb
|
247
267
|
- spec/support/matchers.rb
|
268
|
+
- spec/support/worker_class.rb
|