sidekiq-merger 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7acc8bcc7c43fe634d4be54f9a4ce5c09135da27
4
- data.tar.gz: ae19824415ac8fe3a38cd876977334f7e41ffaa2
3
+ metadata.gz: c2966632f9d19e7a52b7394eb98d0fe8b114e9ba
4
+ data.tar.gz: 2ade2314686d38e8b93c62be6aee28878ef3eac9
5
5
  SHA512:
6
- metadata.gz: 8fe75f849916a6c70177f68bc9f4326b873d7715e43efdc42db5f26206f7561dd2db4a986c229e32fbe43e40b915ac769db94c6d03b10aaab0a78d27a777e9e5
7
- data.tar.gz: 6a0ef14b3ebac1b36ff959da8d35a28454757b5cbe4ea89efb0799fec10d2c34f4d7e324e67b482c432f24812758f79d640401ad1bec877419abcb2e0dc1cf78
6
+ metadata.gz: b4eb0461a1a436e3a1a5b96afafa36a094e1b6c5a658dd40727766283ec6d6a5f2a8b19d5a93fad528e9ec6ce138bf756b2a80ec2d7f4afe9f17af293c8cff63
7
+ data.tar.gz: bdcc4958eaba9693a28e2a6707280a9e7a563e72b00c339b2e36cbd8549eb43026668ad3248ef8f956beef520403a157102321f9579b548f8020d663334a0419
data/.codeclimate.yml ADDED
@@ -0,0 +1,3 @@
1
+ exclude_paths:
2
+ - "app/"
3
+ - "spec/"
data/.travis.yml CHANGED
@@ -4,6 +4,13 @@ rvm:
4
4
  - 2.2.6
5
5
  - 2.3.3
6
6
  - 2.4.0
7
+ env:
8
+ -
9
+ - SIDEKIQ_VERSION=3.4.0
10
+ - SIDEKIQ_VERSION=3.5.0
11
+ - SIDEKIQ_VERSION=4.0.0
12
+ - SIDEKIQ_VERSION=4.1.0
13
+ - SIDEKIQ_VERSION=4.2.0
7
14
  services:
8
15
  - redis-server
9
16
  before_install:
@@ -12,3 +19,5 @@ before_install:
12
19
  script:
13
20
  - "bundle exec rake spec"
14
21
  - "bundle exec rubocop -D"
22
+ notifications:
23
+ email: false
data/Dockerfile CHANGED
@@ -1,10 +1,13 @@
1
1
  FROM ruby:2.3.3
2
2
  MAINTAINER dtaniwaki
3
3
 
4
- ENV PORT ${PORT:-3000}
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 3000
13
+ EXPOSE $PORT
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ gemspec
4
4
 
5
5
  gem "gem-release"
6
6
  gem "pry"
7
+
8
+ gem "sidekiq", "~> #{ENV["SIDEKIQ_VERSION"]}" unless ENV["SIDEKIQ_VERSION"].nil?
data/README.md CHANGED
@@ -6,8 +6,20 @@
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
+ ## Use Case
14
+
15
+ ### Cancel Task
16
+
17
+ ![Cancel Task](misc/cancel_task_flow.png)
18
+
19
+ ### Bulk Notification
20
+
21
+ ![Bulk Notification](misc/bulk_notification_flow.png)
22
+
11
23
  ## Installation
12
24
 
13
25
  Add this line to your application's Gemfile:
@@ -133,4 +145,5 @@ Copyright (c) 2017 dtaniwaki. See [LICENSE](LICENSE) for details.
133
145
  [cov-link]: https://coveralls.io/r/dtaniwaki/sidekiq-merger
134
146
  [gpa-image]: https://codeclimate.com/github/dtaniwaki/sidekiq-merger.svg
135
147
  [gpa-link]: https://codeclimate.com/github/dtaniwaki/sidekiq-merger
136
-
148
+ [docker-hub-image]: http://dockeri.co/image/dtaniwaki/sidekiq-merger
149
+ [docker-hub-link]: https://hub.docker.com/r/dtaniwaki/sidekiq-merger/
data/app/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- sidekiq-merger (0.0.6)
4
+ sidekiq-merger (0.0.9)
5
5
  activesupport (>= 3.2, < 6)
6
6
  concurrent-ruby (~> 1.0)
7
7
  sidekiq (>= 3.4, < 5)
@@ -16,7 +16,7 @@ GEM
16
16
  tzinfo (~> 1.1)
17
17
  concurrent-ruby (1.0.4)
18
18
  connection_pool (2.2.1)
19
- i18n (0.7.0)
19
+ i18n (0.8.0)
20
20
  minitest (5.10.1)
21
21
  rack (1.6.5)
22
22
  rack-flash3 (1.0.5)
data/app/views/index.erb CHANGED
@@ -1,35 +1,62 @@
1
- <html>
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">
4
6
  </head>
5
7
  <body>
6
- <h1>Sidekiq Merger</h1>
7
- <% if flash[:notice] %>
8
- <p style="color: green; font-weight: bold;"><%= flash[:notice] %></p>
9
- <% end %>
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>
8
+ <header class="navbar">
9
+ <div class="container">
10
+ <h1>Sidekiq Merger</h1>
11
+ <a href="https://github.com/dtaniwaki/sidekiq-merger">View Source on GitHub →</a>
23
12
  </div>
24
- <h3>UniqueWorker</h3>
13
+ </header>
14
+ <div class="container">
15
+ <% if flash[:notice] %>
16
+ <div class="alert alert-info">
17
+ <a href="#" class="close" data-dismiss="alert">&times;</a>
18
+ <p><%= flash[:notice] %></p>
19
+ </div>
20
+ <% end %>
21
+ <p class="lead">
22
+ Click the `perform_in` buttons to create or merge tasks until the execution time (in 60s).<br>
23
+ Click the `perform_async` buttons to execute a single task.<br><br>
24
+ Open <a href="/sidekiq/merges?poll=true" target="_blank">sidekiq console</a> to check what happens.
25
+ </p>
25
26
  <div>
26
- <form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
27
- <input type="submit" name="perform_in" value="perform_in">
28
- </form>
29
- <form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
30
- <input type="submit" name="perform_async" value="perform_async">
31
- </form>
27
+ <h2>SomeWorker</h2>
28
+ <p>
29
+ <code>sidekiq_options merger: { unique: false }</code>
30
+ </p>
31
+ <p class="lead">
32
+ <small>Tasks will be merged regardless of uniqueness.</small>
33
+ </p>
34
+ <div>
35
+ <form action="/some_worker/perform_in" method="post" style="display: inline-block;">
36
+ <input type="submit" name="perform_in" value="perform_in" class="btn btn-primary">
37
+ </form>
38
+ <form action="/some_worker/perform_in" method="post" style="display: inline-block;">
39
+ <input type="submit" name="perform_async" value="perform_async" class="btn btn-default">
40
+ </form>
41
+ </div>
42
+ <h2>UniqueWorker</h2>
43
+ <p>
44
+ <code>sidekiq_options merger: { unique: true }</code>
45
+ </p>
46
+ <p class="lead">
47
+ <small>Tasks will be merged if they haven't added already.</small>
48
+ </p>
49
+ <div>
50
+ <form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
51
+ <input type="submit" name="perform_in" value="perform_in" class="btn btn-primary">
52
+ </form>
53
+ <form action="/unique_worker/perform_in" method="post" style="display: inline-block;">
54
+ <input type="submit" name="perform_async" value="perform_async" class="btn btn-default">
55
+ </form>
56
+ </div>
32
57
  </div>
33
58
  </div>
59
+ <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
60
+ <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
34
61
  </body>
35
62
  </html>
data/docker-compose.yml CHANGED
@@ -20,7 +20,8 @@ services:
20
20
  links:
21
21
  - redis
22
22
  environment:
23
+ - PORT=3000
23
24
  - REDIS_HOST=redis
24
25
  - REDIS_PORT=6379
25
26
  redis:
26
- image: redis:latest
27
+ image: redis:3.2.7
@@ -22,6 +22,14 @@ module Sidekiq::Merger
22
22
  task.add_observer(observer)
23
23
  task
24
24
  end
25
+
26
+ def configure(&block)
27
+ yield config
28
+ end
29
+
30
+ def config
31
+ @config ||= Config.new
32
+ end
25
33
  end
26
34
 
27
35
  self.logger = Sidekiq.logger
@@ -1,6 +1,6 @@
1
1
  require "active_support/configurable"
2
2
 
3
- module Sidekiq::Merger::Config
3
+ class Sidekiq::Merger::Config
4
4
  include ActiveSupport::Configurable
5
5
 
6
6
  def self.options
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Merger
3
- VERSION = "0.0.9".freeze
3
+ VERSION = "0.0.10".freeze
4
4
  end
5
5
  end
Binary file
Binary file
@@ -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(:options) { { key: -> (args) { args.to_json } } }
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(:options) { {} }
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(:options) { { key: "bar" } }
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(:options) { { key: [1, 2, 3] } }
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(:options) { { key: -> (args) { args[0].to_s } } }
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(:options) { { key: -> (args) { args[0] } } }
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("name:queue:foo", [1, 2, 3], execution_time)
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(:options) { { key: -> (args) { args.to_json }, unique: true } }
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("name:queue:foo", [1, 2, 3], execution_time)
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("name:queue:foo", [1, 2, 3])
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
@@ -195,7 +180,7 @@ describe Sidekiq::Merger::Merge do
195
180
 
196
181
  describe "#full_merge_key" do
197
182
  it "returns full merge key" do
198
- expect(subject.full_merge_key).to eq "name:queue:foo"
183
+ expect(subject.full_merge_key).to eq "some_worker:queue:foo"
199
184
  end
200
185
  end
201
186
  end
@@ -1,28 +1,11 @@
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
 
@@ -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 "#create_task" do
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
 
@@ -59,9 +43,12 @@ RSpec.configure do |config|
59
43
  Sidekiq.logger = nil
60
44
  end
61
45
 
62
- config.before :example do
63
- Sidekiq::Merger::Redis.redis do |conn|
64
- conn.flushall
46
+ config.around :example do |example|
47
+ Sidekiq::Merger::Redis.redis { |conn| conn.flushall }
48
+ begin
49
+ example.run
50
+ ensure
51
+ Sidekiq::Merger::Redis.redis { |conn| conn.flushall }
65
52
  end
66
53
  end
67
54
 
@@ -0,0 +1,34 @@
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
+ before :example do
23
+ allow(Object).to receive(:const_get).with(anything).and_call_original
24
+ allow(Object).to receive(:const_get).with("SomeWorker").and_return worker_class
25
+ end
26
+ around :example do |example|
27
+ worker_class.jobs.clear
28
+ begin
29
+ example.run
30
+ ensure
31
+ worker_class.jobs.clear
32
+ end
33
+ end
34
+ 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.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - dtaniwaki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-01 00:00:00.000000000 Z
11
+ date: 2017-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -167,6 +167,7 @@ executables: []
167
167
  extensions: []
168
168
  extra_rdoc_files: []
169
169
  files:
170
+ - ".codeclimate.yml"
170
171
  - ".dockerignore"
171
172
  - ".gemrelease"
172
173
  - ".gitignore"
@@ -199,6 +200,8 @@ files:
199
200
  - lib/sidekiq/merger/version.rb
200
201
  - lib/sidekiq/merger/views/index.erb
201
202
  - lib/sidekiq/merger/web.rb
203
+ - misc/bulk_notification_flow.png
204
+ - misc/cancel_task_flow.png
202
205
  - misc/web_ui.png
203
206
  - sidekiq-merger.gemspec
204
207
  - spec/sidekiq/merger/flusher_spec.rb
@@ -209,6 +212,7 @@ files:
209
212
  - spec/sidekiq/merger_spec.rb
210
213
  - spec/spec_helper.rb
211
214
  - spec/support/matchers.rb
215
+ - spec/support/worker_class.rb
212
216
  homepage: https://github.com/dtaniwaki/sidekiq-merger
213
217
  licenses:
214
218
  - MIT
@@ -245,3 +249,4 @@ test_files:
245
249
  - spec/sidekiq/merger_spec.rb
246
250
  - spec/spec_helper.rb
247
251
  - spec/support/matchers.rb
252
+ - spec/support/worker_class.rb