sidekiq-debouncer 2.0.2 → 3.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bab3413954e727ee13bc4d216f13621d1337df24f1ed970ecf146fae30501ef6
4
- data.tar.gz: 883a815a2bb23e08abb175bf04f0231e028684d174c3d60bef6cc1450294764d
3
+ metadata.gz: 0a48a55ff72c620ec5c777c51d93008502eee9a5a5e6ac5678936a0a937f9300
4
+ data.tar.gz: a3a99b8171604c90d3e3fb2ee2665e8601d2a53e22cae488d7a3018f298c734a
5
5
  SHA512:
6
- metadata.gz: 254b6d10c2cf611d91e6971f9e21cc76964600ab951f718c88aa0d7eacb38fe3fccc4bd4f0e0f971d33e829e5a6ce0997d5c1a7a9886bc95e503a554b57e0241
7
- data.tar.gz: 8d5877eec61fb2dbac4305db1815afc320306e0c1af78a872468a5a2218dd48f4b9f8a954e323e59aa3d088b783ae61cc14140a987c3f0785c80a3621c0dcbf7
6
+ metadata.gz: caf0fe8240dd387090d730f7421ed6f92897bbbb770410b7f2861f1bf898f261c8cf801519c9f974c50e9a4929fff3da5f275280bca4de4506bf17ea48fbaff4
7
+ data.tar.gz: 262ca59401d304f301413beda565c40f2557a2352f156ad84e9422e0ab2cf30006e7038e31bcbb67c80ecbe4a575880a3074e6ec74657c74fca4ce250f645c61
data/CHANGELOG.md CHANGED
@@ -1,4 +1,16 @@
1
- ## Unreleased
1
+ ## [3.1.0] - 2025-03-28
2
+ - Drop support for Ruby < 3.2.0
3
+ - Support for Sidekiq 8 ([#31](https://github.com/paladinsoftware/sidekiq-debouncer/pull/31), [#32](https://github.com/paladinsoftware/sidekiq-debouncer/pull/32))
4
+ - DragonflyDB support ([#29](https://github.com/paladinsoftware/sidekiq-debouncer/pull/29))
5
+
6
+ ## [3.0.0] - 2024-10-22
7
+ - Complete rewrite of the library ([#25](https://github.com/paladinsoftware/sidekiq-debouncer/pull/25))
8
+ - Read only Web UI ([#26](https://github.com/paladinsoftware/sidekiq-debouncer/pull/26))
9
+ - Drop support for sidekiq 6.x and ruby 2.7 ([#28](https://github.com/paladinsoftware/sidekiq-debouncer/pull/28))
10
+ - Respect sidekiq_options overridden by .set ([#27](https://github.com/paladinsoftware/sidekiq-debouncer/pull/27))
11
+
12
+ **Upgrade notes:**
13
+ Since the job format changed, V3 won't debounce jobs enqueued with V2, although they'll still get executed
2
14
 
3
15
  ## [2.0.2] - 2023-03-13
4
16
  - support Sidekiq::Testing
@@ -7,7 +19,7 @@
7
19
  - don't remove debounce key in redis to avoid invalid debouncing
8
20
 
9
21
  ## [2.0.0] - 2023-02-28
10
- Complete rewrite of the library:
22
+ Complete rewrite of the library:
11
23
  - Instead of iterating through whole schedule set, sidekiq-debouncer will now cache debounce key in redis with a reference to the job.
12
24
  Thanks to that there is a huge performance boost compared to V1. With 1k jobs in schedule set it's over 100x faster.
13
25
  The difference is even bigger with larger amount of jobs.
data/README.md CHANGED
@@ -99,6 +99,9 @@ Sidekiq.configure_client do |config|
99
99
  end
100
100
  ```
101
101
 
102
+ ## Web UI
103
+ Add `require 'sidekiq/debouncer/web'` after `require 'sidekiq/web'`.
104
+
102
105
  ## Testing
103
106
 
104
107
  In order to test the behavior of `sidekiq-debouncer` it is necessary to disable testing mode. It is the limitation of internal implementation.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sidekiq/scheduled"
4
+
5
+ module Sidekiq
6
+ module Debouncer
7
+ class Enq < ::Sidekiq::Scheduled::Enq
8
+ extend LuaCommands
9
+
10
+ LUA_ZPOPBYSCORE_WITHSCORE = File.read(File.expand_path("../lua/zpopbyscore_withscore.lua", __FILE__))
11
+ LUA_ZPOPBYSCORE_MULTI = File.read(File.expand_path("../lua/zpopbyscore_multi.lua", __FILE__))
12
+
13
+ define_lua_command(:zpopbyscore_withscore, LUA_ZPOPBYSCORE_WITHSCORE)
14
+ define_lua_command(:zpopbyscore_multi, LUA_ZPOPBYSCORE_MULTI)
15
+
16
+ def enqueue_jobs
17
+ redis do |conn|
18
+ while !@done && (job, score = zpopbyscore_withscore(conn, [Sidekiq::Debouncer::SET], [Time.now.to_f.to_s]))
19
+ job_args = zpopbyscore_multi(conn, [job], [score])
20
+
21
+ final_args = job_args.map { |elem| Sidekiq.load_json(elem.split("-", 2)[1]) }
22
+ job_class = job.split("/")[2]
23
+ klass = Object.const_get(job_class)
24
+
25
+ @client.push({"args" => final_args, "class" => klass, "debounce_key" => job})
26
+
27
+ logger.debug { "enqueued #{Sidekiq::Debouncer::SET}: #{job}" }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ module Debouncer
5
+ class Job
6
+ include Sidekiq::JobUtil
7
+
8
+ attr_reader :key, :score
9
+
10
+ def initialize(key, score)
11
+ @key = key
12
+ @score = Float(score)
13
+ end
14
+
15
+ def at
16
+ Time.at(score).utc
17
+ end
18
+
19
+ def args
20
+ @_args ||= Sidekiq.redis { |conn| conn.call("ZRANGE", key, "-inf", "+inf", "BYSCORE") }
21
+ .map { |elem| Sidekiq.load_json(elem.split("-", 2)[1]) }
22
+ end
23
+
24
+ def queue
25
+ normalized["queue"]
26
+ end
27
+
28
+ def klass
29
+ key.split("/")[2]
30
+ end
31
+
32
+ alias_method :display_class, :klass
33
+
34
+ private
35
+
36
+ def normalized
37
+ @_normalized ||= normalize_item({"args" => args, "class" => Object.const_get(klass), "debounce_key" => key})
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ module Debouncer
5
+ module Launcher
6
+ def initialize(config, **kwargs)
7
+ @debounce_poller = Sidekiq::Debouncer::Poller.new(config)
8
+ super
9
+ end
10
+
11
+ def run
12
+ super
13
+ @debounce_poller.start
14
+ end
15
+
16
+ def quiet
17
+ super
18
+ @debounce_poller.terminate
19
+ end
20
+
21
+ def stop
22
+ @debounce_poller.terminate
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ Sidekiq.configure_server do
30
+ require "sidekiq/launcher"
31
+
32
+ ::Sidekiq::Launcher.prepend(Sidekiq::Debouncer::Launcher)
33
+ end
@@ -0,0 +1,4 @@
1
+ en:
2
+ Debounces: Debounces
3
+ DebounceKey: Debounce Key
4
+ NoDebouncesFound: No debounces found
@@ -1,22 +1,10 @@
1
1
  local set = KEYS[1]
2
2
  local debounce_key = KEYS[2]
3
3
 
4
- local job = ARGV[1]
4
+ local args = ARGV[1]
5
5
  local time = ARGV[2]
6
6
  local ttl = ARGV[3]
7
7
 
8
- local existing_debounce = redis.call("GET", debounce_key)
9
-
10
- if existing_debounce then
11
- redis.call("DEL", debounce_key)
12
- -- skip if job wasn't found in schedule set
13
- if redis.call("ZREM", set, existing_debounce) > 0 then
14
- local new_args = cjson.decode(job)['args'][1]
15
- local new_job = cjson.decode(existing_debounce)
16
- table.insert(new_job['args'], new_args)
17
- job = cjson.encode(new_job)
18
- end
19
- end
20
-
21
- redis.call("SET", debounce_key, job, "EX", ttl)
22
- redis.call("ZADD", set, time, job)
8
+ redis.call("ZADD", set, time, debounce_key)
9
+ redis.call("ZADD", debounce_key, time, args)
10
+ redis.call("EXPIRE", debounce_key, ttl)
@@ -0,0 +1,5 @@
1
+ local key, now = KEYS[1], ARGV[1]
2
+ local jobs = redis.call("ZRANGE", key, "-inf", now, "BYSCORE")
3
+ redis.call("ZREMRANGEBYSCORE", key, "-inf", now)
4
+
5
+ return jobs
@@ -0,0 +1,6 @@
1
+ local key, now = KEYS[1], ARGV[1]
2
+ local jobs = redis.call("ZRANGE", key, "-inf", now, "BYSCORE", "LIMIT", 0, 1, "WITHSCORES")
3
+ if jobs[1] then
4
+ redis.call("ZREM", key, jobs[1])
5
+ return {jobs[1], jobs[2]}
6
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha1"
4
+
5
+ module Sidekiq
6
+ module Debouncer
7
+ module LuaCommands
8
+ def define_lua_command(command, script)
9
+ sha = Digest::SHA1.hexdigest(script)
10
+ define_method(command) do |conn, keys, argv|
11
+ retryable = true
12
+ begin
13
+ conn.call("EVALSHA", sha, keys.size, *keys, *argv)
14
+ rescue RedisClient::CommandError => e
15
+ raise if !e.message.start_with?("NOSCRIPT") || !retryable
16
+
17
+ # upload script to redis cache and retry
18
+ conn.call("SCRIPT", "LOAD", script)
19
+ retryable = false
20
+ retry
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest/sha1"
3
+ require "securerandom"
4
4
 
5
5
  module Sidekiq
6
6
  module Debouncer
@@ -11,10 +11,11 @@ module Sidekiq
11
11
  # job from schedule set when another debounce occurs.
12
12
  class Client
13
13
  include Sidekiq::ClientMiddleware
14
+ extend Sidekiq::Debouncer::LuaCommands
14
15
 
15
16
  LUA_DEBOUNCE = File.read(File.expand_path("../../lua/debounce.lua", __FILE__))
16
- LUA_DEBOUNCE_SHA = Digest::SHA1.hexdigest(LUA_DEBOUNCE)
17
- REDIS_ERROR_CLASS = defined?(RedisClient::CommandError) ? RedisClient::CommandError : Redis::CommandError
17
+
18
+ define_lua_command(:redis_debounce, LUA_DEBOUNCE)
18
19
 
19
20
  def initialize(options = {})
20
21
  @debounce_key_ttl = options.fetch(:ttl, 60 * 60 * 24) # 24 hours by default
@@ -35,18 +36,16 @@ module Sidekiq
35
36
  def debounce(klass, job)
36
37
  raise NotSupportedError, "perform_at is not supported with debounce" if job.key?("at")
37
38
 
38
- options = debounce_options(klass)
39
+ options = debounce_options(klass, job)
39
40
  key = debounce_key(klass, job, options)
40
41
  time = (options[:time].to_f + Time.now.to_f).to_s
41
42
 
42
- job["debounce_key"] = key
43
- job["args"] = [job["args"]]
44
- job.delete("debounce")
43
+ return job.merge("args" => [job["args"]], "debounce_key" => key) if testing?
45
44
 
46
- return job if testing?
45
+ args_stringified = "#{SecureRandom.hex(12)}-#{Sidekiq.dump_json(job["args"])}"
47
46
 
48
47
  redis do |connection|
49
- redis_debounce(connection, keys: ["schedule", key], argv: [Sidekiq.dump_json(job), time, @debounce_key_ttl])
48
+ redis_debounce(connection, [Sidekiq::Debouncer::SET, key], [args_stringified, time, @debounce_key_ttl])
50
49
  end
51
50
 
52
51
  # prevent normal sidekiq flow
@@ -56,11 +55,12 @@ module Sidekiq
56
55
  def debounce_key(klass, job, options)
57
56
  method = options[:by]
58
57
  result = method.is_a?(Symbol) ? klass.send(method, job["args"]) : method.call(job["args"])
59
- "debounce/#{klass.name}/#{result}"
58
+ "debounce/v3/#{klass.name}/#{result}"
60
59
  end
61
60
 
62
- def debounce_options(klass)
63
- options = klass.get_sidekiq_options["debounce"].transform_keys(&:to_sym)
61
+ def debounce_options(klass, job)
62
+ options = job.fetch("debounce") { klass.get_sidekiq_options["debounce"] }
63
+ options = options.transform_keys(&:to_sym)
64
64
 
65
65
  raise MissingArgumentError, "'by' attribute not provided" unless options[:by]
66
66
  raise MissingArgumentError, "'time' attribute not provided" unless options[:time]
@@ -68,20 +68,6 @@ module Sidekiq
68
68
  options
69
69
  end
70
70
 
71
- def redis_debounce(connection, keys:, argv:)
72
- retryable = true
73
- begin
74
- connection.call("EVALSHA", LUA_DEBOUNCE_SHA, keys.size, *keys, *argv)
75
- rescue REDIS_ERROR_CLASS => e
76
- raise if !e.message.start_with?("NOSCRIPT") || !retryable
77
-
78
- # upload script to redis cache and retry
79
- connection.call("SCRIPT", "LOAD", LUA_DEBOUNCE)
80
- retryable = false
81
- retry
82
- end
83
- end
84
-
85
71
  def testing?
86
72
  defined?(Sidekiq::Testing) && Sidekiq::Testing.enabled?
87
73
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sidekiq/scheduled"
4
+
5
+ module Sidekiq
6
+ module Debouncer
7
+ class Poller < ::Sidekiq::Scheduled::Poller
8
+ def initialize(config)
9
+ super
10
+ @enq = Sidekiq::Debouncer::Enq.new(config)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ module Debouncer
5
+ class Set < Sidekiq::JobSet
6
+ def initialize
7
+ super Sidekiq::Debouncer::SET
8
+ end
9
+
10
+ def fetch_by_key(key)
11
+ score = Sidekiq.redis { |conn| conn.zscore(Sidekiq::Debouncer::SET, key) }
12
+ Job.new(key, score)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Debouncer
5
- VERSION = "2.0.2"
5
+ VERSION = "3.1.0"
6
6
  end
7
7
  end
@@ -0,0 +1,50 @@
1
+ <section>
2
+ <header class='row'>
3
+ <div class='col-sm-5 pull-left'>
4
+ <h3><%= t('Debounces') %></h3>
5
+ </div>
6
+ <div class='col-sm-7 pull-right'>
7
+ <%= erb :_paging, locals: { url: "#{root_path}debounces" } %>
8
+ </div>
9
+ </header>
10
+
11
+ <% if @debounces.size > 0 %>
12
+ <form action="<%= root_path %>debounces" method="post">
13
+ <%= csrf_tag %>
14
+ <div class="table_container">
15
+ <table class="table table-striped table-bordered table-hover">
16
+ <thead>
17
+ <tr>
18
+ <th class="table-checkbox checkbox-column">
19
+ <label>
20
+ <input type="checkbox" class="check_all" />
21
+ </label>
22
+ </th>
23
+ <th><%= t('When') %></th>
24
+ <th><%= t('DebounceKey') %></th>
25
+ </tr>
26
+ </thead>
27
+ <% @debounces.each do |entry| %>
28
+ <tr>
29
+ <td class="table-checkbox">
30
+ <label>
31
+ <input type='checkbox' name='key[]' value='<%= entry.key %>' class='shift_clickable' />
32
+ </label>
33
+ </td>
34
+ <td>
35
+ <a href="<%= root_path %>debounces/<%= ::Base64.urlsafe_encode64(entry.key) %>"><%= relative_time(entry.at) %></a>
36
+ </td>
37
+ <td>
38
+ <a href="<%= root_path %>debounces/<%= ::Base64.urlsafe_encode64(entry.key) %>"><%= entry.key %></a>
39
+ </td>
40
+ </tr>
41
+ <% end %>
42
+ </table>
43
+ </div>
44
+ <!-- <input class="btn btn-danger pull-right flip" type="submit" name="delete" value="<%#= t('Delete') %>" />-->
45
+ <!-- <input class="btn btn-danger pull-right flip" type="submit" name="add_to_queue" value="<%#= t('AddToQueue') %>" />-->
46
+ </form>
47
+ <% else %>
48
+ <div class="alert alert-success"><%= t('NoDebouncesFound') %></div>
49
+ <% end %>
50
+ </section>
@@ -0,0 +1,40 @@
1
+ <section>
2
+ <header class="header-container">
3
+ <h3><%= t('Job') %></h3>
4
+ </header>
5
+
6
+ <div class="table_container">
7
+ <table class="table table-bordered table-striped table-hover">
8
+ <tbody>
9
+ <tr>
10
+ <th><%= t('Queue') %></th>
11
+ <td><%= @job.queue %></td>
12
+ </tr>
13
+ <tr>
14
+ <th><%= t('When') %></th>
15
+ <td><%= relative_time(@job.at) %></td>
16
+ </tr>
17
+ <tr>
18
+ <th><%= t('DebounceKey') %></th>
19
+ <td>
20
+ <%= @job.key %>
21
+ </td>
22
+ </tr>
23
+ <tr>
24
+ <th><%= t('Job') %></th>
25
+ <td>
26
+ <%= @job.display_class %>
27
+ </td>
28
+ </tr>
29
+ <tr>
30
+ <th><%= t('Arguments') %></th>
31
+ <td>
32
+ <code class="code-wrap">
33
+ <div class="args-extended"><%= display_args(@job.args, nil) %></div>
34
+ </code>
35
+ </td>
36
+ </tr>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+ </section>
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Sidekiq::Web)
4
+ require "sidekiq/debouncer/web_extension"
5
+
6
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
7
+ Sidekiq::Web.configure do |config|
8
+ config.register(
9
+ Sidekiq::Debouncer::WebExtension,
10
+ name: "debounces",
11
+ tab: "Debounces",
12
+ index: "debounces"
13
+ )
14
+ end
15
+ elsif Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("7.3.0")
16
+ Sidekiq::Web.register(
17
+ Sidekiq::Debouncer::WebExtension,
18
+ name: "debounces",
19
+ tab: "Debounces",
20
+ index: "debounces"
21
+ )
22
+ else
23
+ Sidekiq::Web.register Sidekiq::Debouncer::WebExtension
24
+ Sidekiq::Web.tabs["Debounces"] = "debounces"
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ module Sidekiq
6
+ module Debouncer
7
+ module WebExtension
8
+ module Helpers
9
+ def get_route_param(key)
10
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
11
+ route_params(key)
12
+ else
13
+ route_params[key]
14
+ end
15
+ end
16
+
17
+ def get_url_param(key)
18
+ if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
19
+ url_params(key)
20
+ else
21
+ params[key]
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.registered(app)
27
+ locales = if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("8.0.0")
28
+ Sidekiq::Web.configure.locales
29
+ else
30
+ app.settings.locales
31
+ end
32
+
33
+ locales << File.join(File.expand_path("..", __FILE__), "locales")
34
+
35
+ app.helpers(Helpers)
36
+
37
+ app.get "/debounces" do
38
+ view_path = File.join(File.expand_path("..", __FILE__), "views")
39
+
40
+ @count = (get_url_param("count") || 25).to_i
41
+ (@current_page, @total_size, @debounces) = page("debouncer", get_url_param("page"), @count)
42
+ @debounces = @debounces.map { |key, score| Sidekiq::Debouncer::Job.new(key, score) }
43
+
44
+ render(:erb, File.read(File.join(view_path, "index.html.erb")))
45
+ end
46
+
47
+ app.get "/debounces/:key" do
48
+ view_path = File.join(File.expand_path("..", __FILE__), "views")
49
+
50
+ @job = Sidekiq::Debouncer::Set.new.fetch_by_key(Base64.urlsafe_decode64(get_route_param(:key)))
51
+
52
+ render(:erb, File.read(File.join(view_path, "show.html.erb")))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -2,11 +2,16 @@
2
2
 
3
3
  require "sidekiq/debouncer/version"
4
4
  require "sidekiq/debouncer/errors"
5
+ require "sidekiq/debouncer/lua_commands"
5
6
  require "sidekiq/debouncer/middleware/client"
6
7
  require "sidekiq/debouncer/middleware/server"
8
+ require "sidekiq/debouncer/job"
9
+ require "sidekiq/debouncer/set"
7
10
 
8
11
  module Sidekiq
9
12
  module Debouncer
13
+ SET = "debouncer"
14
+
10
15
  def self.included(base)
11
16
  base.extend ClassMethods
12
17
  end
@@ -19,3 +24,9 @@ module Sidekiq
19
24
  end
20
25
  end
21
26
  end
27
+
28
+ Sidekiq.configure_server do
29
+ require "sidekiq/debouncer/enq"
30
+ require "sidekiq/debouncer/poller"
31
+ require "sidekiq/debouncer/launcher"
32
+ end
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  DESCRIPTION
19
19
  gem.homepage = "https://github.com/paladinsoftware/sidekiq-debouncer"
20
20
  gem.license = "MIT"
21
- gem.required_ruby_version = ">= 2.7.0"
21
+ gem.required_ruby_version = ">= 3.0.0"
22
22
 
23
23
  gem.files = Dir.glob("lib/**/*") + [
24
24
  "CHANGELOG.md",
@@ -27,11 +27,13 @@ Gem::Specification.new do |gem|
27
27
  "sidekiq-debouncer.gemspec"
28
28
  ]
29
29
 
30
- gem.add_dependency "sidekiq", ">= 6.5", "< 8.0"
30
+ gem.add_dependency "sidekiq", ">= 7.0", "< 9.0"
31
31
 
32
32
  gem.add_development_dependency "rspec", "~> 3.12.0"
33
33
  gem.add_development_dependency "timecop", "~> 0.9.6"
34
34
  gem.add_development_dependency "simplecov", "~> 0.22.0"
35
35
  gem.add_development_dependency "parallel", "~> 1.22.1"
36
36
  gem.add_development_dependency "standard", "~> 1.24.3"
37
+ gem.add_development_dependency "rack-test", "~> 2.1.0"
38
+ gem.add_development_dependency "rack-session", "~> 2.1.0"
37
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-debouncer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Zuchmański
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-13 00:00:00.000000000 Z
12
+ date: 2025-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -17,20 +17,20 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '6.5'
20
+ version: '7.0'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '8.0'
23
+ version: '9.0'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: '6.5'
30
+ version: '7.0'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '8.0'
33
+ version: '9.0'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: rspec
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +101,34 @@ dependencies:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: 1.24.3
104
+ - !ruby/object:Gem::Dependency
105
+ name: rack-test
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.1.0
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.1.0
118
+ - !ruby/object:Gem::Dependency
119
+ name: rack-session
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 2.1.0
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 2.1.0
104
132
  description: |
105
133
  Sidekiq extension that adds the ability to debounce job execution.
106
134
  Worker will postpone its execution after `wait time` have elapsed since the last time it was invoked.
@@ -117,11 +145,24 @@ files:
117
145
  - README.md
118
146
  - lib/sidekiq-debouncer.rb
119
147
  - lib/sidekiq/debouncer.rb
148
+ - lib/sidekiq/debouncer/enq.rb
120
149
  - lib/sidekiq/debouncer/errors.rb
150
+ - lib/sidekiq/debouncer/job.rb
151
+ - lib/sidekiq/debouncer/launcher.rb
152
+ - lib/sidekiq/debouncer/locales/en.yml
121
153
  - lib/sidekiq/debouncer/lua/debounce.lua
154
+ - lib/sidekiq/debouncer/lua/zpopbyscore_multi.lua
155
+ - lib/sidekiq/debouncer/lua/zpopbyscore_withscore.lua
156
+ - lib/sidekiq/debouncer/lua_commands.rb
122
157
  - lib/sidekiq/debouncer/middleware/client.rb
123
158
  - lib/sidekiq/debouncer/middleware/server.rb
159
+ - lib/sidekiq/debouncer/poller.rb
160
+ - lib/sidekiq/debouncer/set.rb
124
161
  - lib/sidekiq/debouncer/version.rb
162
+ - lib/sidekiq/debouncer/views/index.html.erb
163
+ - lib/sidekiq/debouncer/views/show.html.erb
164
+ - lib/sidekiq/debouncer/web.rb
165
+ - lib/sidekiq/debouncer/web_extension.rb
125
166
  - sidekiq-debouncer.gemspec
126
167
  homepage: https://github.com/paladinsoftware/sidekiq-debouncer
127
168
  licenses:
@@ -135,14 +176,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
176
  requirements:
136
177
  - - ">="
137
178
  - !ruby/object:Gem::Version
138
- version: 2.7.0
179
+ version: 3.0.0
139
180
  required_rubygems_version: !ruby/object:Gem::Requirement
140
181
  requirements:
141
182
  - - ">="
142
183
  - !ruby/object:Gem::Version
143
184
  version: '0'
144
185
  requirements: []
145
- rubygems_version: 3.3.26
186
+ rubygems_version: 3.5.22
146
187
  signing_key:
147
188
  specification_version: 4
148
189
  summary: Sidekiq extension that adds the ability to debounce job execution