sidekiq-debouncer 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9f505c753200cb5a607d4a0f847372a72f5f5571631d6b50e12348e99b407f30
4
+ data.tar.gz: b72d1d31b9b1b13a7ab8ec88a56a27e2a84e11a8dca721e296ec4a25da361dd7
5
+ SHA512:
6
+ metadata.gz: 400505251465ceca2630d226a8f1017518a5bb068e755a05428e8f00be81519c2ddcda91be840c24f3eaf382ff7302e1c1941fe790eec95a5cb9f9d9f72dd797
7
+ data.tar.gz: 6d01faab4b9f4b98512dadb598100674d241ab3fd99a324e1abb89773a9a4c92ba8782fb1564e68a97d4c171646ec9f6472a25cdb507eba218d739f368f1226f
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .rspec-local
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ gemfiles/*.gemfile.lock
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
@@ -0,0 +1,27 @@
1
+ version: v1.0
2
+ name: Sidekiq-debouncer CI pipeline
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu1804
7
+
8
+ blocks:
9
+ - name: Run specs
10
+ task:
11
+ env_vars:
12
+ - name: RAILS_ENV
13
+ value: "test"
14
+
15
+ jobs:
16
+ - name: Run RSpec
17
+ matrix:
18
+ - env_var: SIDEKIQ_VERSION
19
+ values: [ "5.0.5", "5.1.3", "5.2.7", "6.0.2" ]
20
+ commands:
21
+ - checkout
22
+ - export RUBY_VERSION=$(cat gemfiles/sidekiq-$SIDEKIQ_VERSION.gemfile | grep "ruby \".*\"" | grep -o "[0-9]\.[0-9]\.[0-9]")
23
+ - sem-version ruby $RUBY_VERSION
24
+ - sem-service start redis
25
+ - gem install bundler -v 1.17.3 -N
26
+ - bundle install --gemfile gemfiles/sidekiq-$SIDEKIQ_VERSION.gemfile
27
+ - RAILS_ENV=test bundle exec --gemfile gemfiles/sidekiq-$SIDEKIQ_VERSION.gemfile rspec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Gabriel Evans
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # Sidekiq::Debouncer
2
+
3
+ Sidekiq extension that adds the ability to debounce job execution.
4
+
5
+ Worker will postpone its execution after `wait time` have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: sending group email to the user after he stopped interacting with the application.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sidekiq-debouncer'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Basic usage
20
+
21
+ In a worker, include `Sidekiq::Debouncer` module, specify debounce wait time (in seconds):
22
+
23
+ ```ruby
24
+ class MyWorker
25
+ include Sidekiq::Worker
26
+ include Sidekiq::Debouncer
27
+
28
+ sidekiq_options(
29
+ debounce: {
30
+ time: 5 * 60
31
+ }
32
+ )
33
+
34
+ def perform(group)
35
+ group.each do
36
+ # do some work with group
37
+ end
38
+ end
39
+ end
40
+ ```
41
+
42
+ You can specify your own debounce method. In this case worker will be debounced if first argument matches.
43
+ ```ruby
44
+ class MyWorker
45
+ include Sidekiq::Worker
46
+ include Sidekiq::Debouncer
47
+
48
+ sidekiq_options(
49
+ debounce: {
50
+ time: 5 * 60,
51
+ by: -> (job_args) {
52
+ job_args[0]
53
+ }
54
+ }
55
+ )
56
+
57
+ def perform(group)
58
+ group.each do
59
+ # do some work with group
60
+ end
61
+ end
62
+ end
63
+ ```
64
+
65
+ You can also pass symbol as `debounce_by` matching class method.
66
+ ```ruby
67
+ class MyWorker
68
+ include Sidekiq::Worker
69
+ include Sidekiq::Debouncer
70
+
71
+ sidekiq_options(
72
+ debounce: {
73
+ time: 5 * 60,
74
+ by: :debounce_method
75
+ }
76
+ )
77
+
78
+ def self.debounce_method(job_args)
79
+ job_args[0]
80
+ end
81
+
82
+ def perform(group)
83
+ group.each do
84
+ # do some work with group
85
+ end
86
+ end
87
+ end
88
+ ```
89
+
90
+
91
+ In the application, call `MyWorker.debounce(...)`. Everytime you call this function, `MyWorker`'s execution will be postponed by 5 minutes. After that time `MyWorker` will receive a method call `perform` with an array of arguments that were provided to the `MyWorker.debounce(...)`.
92
+
93
+ ## License
94
+
95
+ MIT Licensed. See LICENSE.txt for details.
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.3.8"
4
+
5
+ gem "sidekiq", "= 5.0.5"
6
+
7
+ gemspec path: '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.4.6"
4
+
5
+ gem "sidekiq", "= 5.1.3"
6
+
7
+ gemspec path: '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.5.5"
4
+
5
+ gem "sidekiq", "= 5.2.7"
6
+
7
+ gemspec path: '../'
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby "2.6.5"
4
+
5
+ gem "sidekiq", "= 6.0.2"
6
+
7
+ gemspec path: '../'
@@ -0,0 +1,48 @@
1
+ require 'sidekiq'
2
+ require 'sidekiq/api'
3
+
4
+ require 'sidekiq/debouncer/version'
5
+
6
+ module Sidekiq
7
+ module Debouncer
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ DEFAULT_DEBOUNCE_FOR = 5 * 60 # 5.minutes
14
+ DEFAULT_DEBOUNCE_BY = -> (job_args) { 0 }
15
+
16
+ def debounce(*args)
17
+ sidekiq_options["debounce"] ||= {}
18
+
19
+ debounce_for = sidekiq_options["debounce"][:time] || DEFAULT_DEBOUNCE_FOR
20
+ debounce_by = sidekiq_options["debounce"][:by] || DEFAULT_DEBOUNCE_BY
21
+ debounce_by_value = debounce_by.is_a?(Symbol) ? send(debounce_by, args) : debounce_by.call(args)
22
+
23
+ ss = Sidekiq::ScheduledSet.new
24
+ jobs = ss.select do |job|
25
+ next false unless job.klass == self.to_s
26
+
27
+ debounce_by_value_job = debounce_by.is_a?(Symbol) ? send(debounce_by, job.args[0][0]) : debounce_by.call(job.args[0][0])
28
+
29
+ debounce_by_value_job == debounce_by_value
30
+ end
31
+
32
+ time_from_now = Time.now + debounce_for
33
+ jobs_to_group = []
34
+
35
+ jobs.each do |job|
36
+ if job.at > Time.now && job.at < time_from_now
37
+ jobs_to_group += job.args[0]
38
+ job.delete
39
+ end
40
+ end
41
+
42
+ jobs_to_group << args
43
+
44
+ perform_in(debounce_for, jobs_to_group)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Sidekiq
2
+ module Debouncer
3
+ VERSION = '1.0.1'.freeze
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sidekiq/debouncer/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'sidekiq-debouncer'
8
+ gem.version = Sidekiq::Debouncer::VERSION
9
+ gem.authors = ['Sebastian Zuchmański', 'Karol Bąk']
10
+ gem.email = ['sebcioz@gmail.com', 'karol.bak@paladinsoftware.com']
11
+ gem.description = %q{Sidekiq extension that adds the ability to debounce job execution.}
12
+ gem.summary = %q{}
13
+ gem.homepage = 'https://github.com/paladinsoftware/sidekiq-debouncer'
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = %w(lib)
19
+
20
+ gem.add_dependency 'activesupport'
21
+ gem.add_dependency 'sidekiq', '>= 5.0'
22
+
23
+ gem.add_development_dependency 'rspec'
24
+ gem.add_development_dependency 'rspec-sidekiq'
25
+ gem.add_development_dependency 'timecop'
26
+ gem.add_development_dependency 'rspec-redis_helper'
27
+ gem.add_development_dependency 'redis-namespace'
28
+ end
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+
3
+ class TestWorker
4
+ include Sidekiq::Worker
5
+ include Sidekiq::Debouncer
6
+
7
+ sidekiq_options(
8
+ debounce: {
9
+ time: 5 * 60,
10
+ by: -> (job_args) {
11
+ job_args[0]
12
+ }
13
+ }
14
+ )
15
+
16
+ # group - array of arguments for single job
17
+ def perform(group)
18
+ group.each do
19
+ # do some work with group
20
+ end
21
+ end
22
+ end
23
+
24
+ class TestWorkerWithMultipleArguments
25
+ include Sidekiq::Worker
26
+ include Sidekiq::Debouncer
27
+
28
+ sidekiq_options(
29
+ debounce: {
30
+ time: 5 * 60,
31
+ by: -> (job_args) {
32
+ job_args[0] + job_args[1]
33
+ }
34
+ }
35
+ )
36
+
37
+ # group - array of arguments for single job
38
+ def perform(group)
39
+ group.each do
40
+ # do some work with group
41
+ end
42
+ end
43
+ end
44
+
45
+ class TestWorkerWithSymbolAsDebounce
46
+ include Sidekiq::Worker
47
+ include Sidekiq::Debouncer
48
+
49
+ sidekiq_options(
50
+ debounce: {
51
+ time: 5 * 60,
52
+ by: :debounce_method
53
+ }
54
+ )
55
+
56
+ def self.debounce_method(args)
57
+ args[0]
58
+ end
59
+
60
+ # group - array of arguments for single job
61
+ def perform(group)
62
+ group.each do
63
+ # do some work with group
64
+ end
65
+ end
66
+ end
67
+
68
+ describe Sidekiq::Debouncer do
69
+ let(:time_start) { Time.new(2016, 1, 1, 12, 0, 0) }
70
+
71
+ before do
72
+ Timecop.freeze(time_start)
73
+ Sidekiq::ScheduledSet.new.clear
74
+ Sidekiq::Testing.disable!
75
+ end
76
+
77
+ context "1 type of tasks" do
78
+ context "1 task" do
79
+ it "executes it after 5 minutes" do
80
+ TestWorker.debounce("A", "job 1")
81
+
82
+ expect(Sidekiq::ScheduledSet.new.size).to eq(1)
83
+
84
+ group = Sidekiq::ScheduledSet.new.first
85
+ expect(group.args[0]).to eq([["A", "job 1"]])
86
+ expect(group.at.to_i).to eq((time_start + 5 * 60).to_i)
87
+ end
88
+
89
+ it "executes it after 5 minutes for symbol debounce" do
90
+ expect(TestWorkerWithSymbolAsDebounce).to receive(:debounce_method).with(["A", "job 1"]).once.and_call_original
91
+ TestWorkerWithSymbolAsDebounce.debounce("A", "job 1")
92
+
93
+ expect(Sidekiq::ScheduledSet.new.size).to eq(1)
94
+
95
+ group = Sidekiq::ScheduledSet.new.first
96
+ expect(group.args[0]).to eq([["A", "job 1"]])
97
+ expect(group.at.to_i).to eq((time_start + 5 * 60).to_i)
98
+ end
99
+ end
100
+
101
+ context "1 task, 3 minutes break, 1 task" do
102
+ it "executes both tasks after 8 minutes for multiple arguments" do
103
+ TestWorkerWithMultipleArguments.debounce(1, 5)
104
+ Timecop.freeze(time_start + 3 * 60)
105
+ TestWorkerWithMultipleArguments.debounce(3, 3)
106
+
107
+ expect(Sidekiq::ScheduledSet.new.size).to eq(1)
108
+ group = Sidekiq::ScheduledSet.new.first
109
+ expect(group.args[0]).to eq([[1, 5], [3, 3]])
110
+ expect(group.at.to_i).to be((time_start + 8 * 60).to_i)
111
+ end
112
+
113
+ it "executes both tasks after 8 minutes" do
114
+ TestWorker.debounce("A", "job 1")
115
+ Timecop.freeze(time_start + 3 * 60)
116
+ TestWorker.debounce("A", "job 2")
117
+
118
+ expect(Sidekiq::ScheduledSet.new.size).to eq(1)
119
+ group = Sidekiq::ScheduledSet.new.first
120
+ expect(group.args[0]).to eq([["A", "job 1"], ["A", "job 2"]])
121
+ expect(group.at.to_i).to be((time_start + 8 * 60).to_i)
122
+ end
123
+
124
+ it "executes both tasks after 8 minutes for symbol debounce" do
125
+ TestWorkerWithSymbolAsDebounce.debounce("A", "job 1")
126
+ Timecop.freeze(time_start + 3 * 60)
127
+ TestWorkerWithSymbolAsDebounce.debounce("A", "job 2")
128
+
129
+ expect(Sidekiq::ScheduledSet.new.size).to eq(1)
130
+ group = Sidekiq::ScheduledSet.new.first
131
+ expect(group.args[0]).to eq([["A", "job 1"], ["A", "job 2"]])
132
+ expect(group.at.to_i).to be((time_start + 8 * 60).to_i)
133
+ end
134
+ end
135
+
136
+ context "1 task, 3 minutes break, 1 task, 6 minutes break, 1 task" do
137
+ it "executes two tasks after 8 minutes, the last one in 14 minutes" do
138
+ TestWorker.debounce("A", "job 1")
139
+ Timecop.freeze(time_start + 3 * 60)
140
+ TestWorker.debounce("A", "job 2")
141
+ Timecop.freeze(time_start + 3 * 60 + 6 * 60)
142
+ TestWorker.debounce("A", "job 3")
143
+
144
+ expect(Sidekiq::ScheduledSet.new.size).to eq(2)
145
+
146
+ groups = Sidekiq::ScheduledSet.new.to_a.sort_by { |g| g.at.to_i }
147
+
148
+ expect(groups[0].args[0]).to eq([["A", "job 1"], ["A", "job 2"]])
149
+ expect(groups[0].at.to_i).to be((time_start + 8 * 60).to_i)
150
+
151
+ expect(groups[1].args[0]).to eq([["A", "job 3"]])
152
+ expect(groups[1].at.to_i).to be((time_start + 14 * 60).to_i)
153
+ end
154
+ end
155
+
156
+ context "1 task, 6 minutes break, 1 task" do
157
+ it "executes first task, the second one in 11 minutes" do
158
+ TestWorker.debounce("A", "job 1")
159
+ Timecop.freeze(time_start + 6 * 60)
160
+ TestWorker.debounce("A", "job 2")
161
+
162
+ expect(Sidekiq::ScheduledSet.new.size).to eq(2)
163
+
164
+ groups = Sidekiq::ScheduledSet.new.to_a.sort_by { |g| g.at.to_i }
165
+
166
+ expect(groups[0].args[0]).to eq([["A", "job 1"]])
167
+ expect(groups[0].at.to_i).to be((time_start + 5 * 60).to_i)
168
+
169
+ expect(groups[1].args[0]).to eq([["A", "job 2"]])
170
+ expect(groups[1].at.to_i).to be((time_start + 11 * 60).to_i)
171
+ end
172
+ end
173
+ end
174
+
175
+ context "two types of tasks" do
176
+ context "A task, 3 minutes break, A and B tasks, 3 minutes break, B task, 6 minutes break, B task" do
177
+ it "executes two A tasks after 8 minuts, two B tasks after 11 minutes, last B task after 17 minutes" do
178
+ TestWorker.debounce("A", "job 1")
179
+ Timecop.freeze(time_start + 3 * 60)
180
+ TestWorker.debounce("A", "job 2")
181
+ TestWorker.debounce("B", "job 3")
182
+ Timecop.freeze(time_start + 3 * 60 + 3 * 60)
183
+ TestWorker.debounce("B", "job 4")
184
+ Timecop.freeze(time_start + 3 * 60 + 3 * 60 + 6 * 60)
185
+ TestWorker.debounce("B", "job 5")
186
+
187
+ expect(Sidekiq::ScheduledSet.new.size).to eq(3)
188
+
189
+ groups = Sidekiq::ScheduledSet.new.to_a.sort_by { |g| g.at.to_i }
190
+
191
+ expect(groups[0].args[0]).to eq([["A", "job 1"], ["A", "job 2"]])
192
+ expect(groups[0].at.to_i).to be((time_start + 8 * 60).to_i)
193
+
194
+ expect(groups[1].args[0]).to eq([["B", "job 3"], ["B", "job 4"]])
195
+ expect(groups[1].at.to_i).to be((time_start + 11 * 60).to_i)
196
+
197
+ expect(groups[2].args[0]).to eq([["B", "job 5"]])
198
+ expect(groups[2].at.to_i).to be((time_start + 17 * 60).to_i)
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rspec'
5
+ require 'redis/namespace'
6
+ require 'rspec-sidekiq'
7
+ require 'timecop'
8
+
9
+ require 'sidekiq/debouncer'
10
+
11
+ RSpec.configure do |config|
12
+ config.order = 'random'
13
+ config.color = true
14
+
15
+ Sidekiq.configure_server do |config|
16
+ config.redis[:namespace] = { namespace: 'sidekiq-debouncer' }
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-debouncer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Zuchmański
8
+ - Karol Bąk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-10-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: sidekiq
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '5.0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '5.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec-sidekiq
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: timecop
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec-redis_helper
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: redis-namespace
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ description: Sidekiq extension that adds the ability to debounce job execution.
113
+ email:
114
+ - sebcioz@gmail.com
115
+ - karol.bak@paladinsoftware.com
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - ".gitignore"
121
+ - ".semaphore/semaphore.yml"
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - gemfiles/sidekiq-5.0.5.gemfile
126
+ - gemfiles/sidekiq-5.1.3.gemfile
127
+ - gemfiles/sidekiq-5.2.7.gemfile
128
+ - gemfiles/sidekiq-6.0.2.gemfile
129
+ - lib/sidekiq/debouncer.rb
130
+ - lib/sidekiq/debouncer/version.rb
131
+ - sidekiq-debounce.gemspec
132
+ - spec/sidekiq/debouncer_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: https://github.com/paladinsoftware/sidekiq-debouncer
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubygems_version: 3.0.6
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: ''
157
+ test_files:
158
+ - spec/sidekiq/debouncer_spec.rb
159
+ - spec/spec_helper.rb