sidekiq-unique-jobs 7.0.0.beta26 → 7.0.1

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.

Potentially problematic release.


This version of sidekiq-unique-jobs might be problematic. Click here for more details.

Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -11
  3. data/README.md +154 -36
  4. data/lib/sidekiq-unique-jobs.rb +0 -2
  5. data/lib/sidekiq_unique_jobs.rb +1 -0
  6. data/lib/sidekiq_unique_jobs/changelog.rb +11 -4
  7. data/lib/sidekiq_unique_jobs/config.rb +2 -2
  8. data/lib/sidekiq_unique_jobs/constants.rb +4 -0
  9. data/lib/sidekiq_unique_jobs/digests.rb +1 -1
  10. data/lib/sidekiq_unique_jobs/job.rb +1 -1
  11. data/lib/sidekiq_unique_jobs/lock/validator.rb +2 -1
  12. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +1 -1
  13. data/lib/sidekiq_unique_jobs/lock_args.rb +4 -4
  14. data/lib/sidekiq_unique_jobs/lock_config.rb +2 -0
  15. data/lib/sidekiq_unique_jobs/locksmith.rb +1 -1
  16. data/lib/sidekiq_unique_jobs/lua/delete_by_digest.lua +1 -1
  17. data/lib/sidekiq_unique_jobs/lua/lock.lua +1 -2
  18. data/lib/sidekiq_unique_jobs/lua/reap_orphans.lua +8 -7
  19. data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_process_set.lua +9 -2
  20. data/lib/sidekiq_unique_jobs/middleware.rb +0 -57
  21. data/lib/sidekiq_unique_jobs/on_conflict/replace.rb +9 -8
  22. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +1 -1
  23. data/lib/sidekiq_unique_jobs/orphans/lua_reaper.rb +1 -1
  24. data/lib/sidekiq_unique_jobs/orphans/reaper.rb +10 -0
  25. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +9 -2
  26. data/lib/sidekiq_unique_jobs/redis/entity.rb +9 -3
  27. data/lib/sidekiq_unique_jobs/redis/sorted_set.rb +27 -0
  28. data/lib/sidekiq_unique_jobs/server.rb +48 -0
  29. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +1 -1
  30. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +1 -1
  31. data/lib/sidekiq_unique_jobs/testing.rb +2 -1
  32. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  33. data/lib/sidekiq_unique_jobs/web.rb +26 -9
  34. data/lib/sidekiq_unique_jobs/web/helpers.rb +24 -3
  35. data/lib/sidekiq_unique_jobs/web/views/changelogs.erb +54 -0
  36. data/lib/sidekiq_unique_jobs/web/views/locks.erb +1 -1
  37. metadata +25 -9
  38. data/lib/sidekiq_unique_jobs/profiler.rb +0 -55
@@ -48,10 +48,10 @@ module SidekiqUniqueJobs
48
48
  def exist?
49
49
  redis do |conn|
50
50
  value = conn.exists(key)
51
- return true if value.is_a?(TrueClass)
52
- return false if value.is_a?(FalseClass)
53
51
 
54
- value.positive?
52
+ return value if boolean?(value)
53
+
54
+ value.to_i.positive?
55
55
  end
56
56
  end
57
57
 
@@ -95,6 +95,12 @@ module SidekiqUniqueJobs
95
95
  def count
96
96
  0
97
97
  end
98
+
99
+ private
100
+
101
+ def boolean?(value)
102
+ [TrueClass, FalseClass].any? { |klazz| value.is_a?(klazz) }
103
+ end
98
104
  end
99
105
  end
100
106
  end
@@ -23,6 +23,23 @@ module SidekiqUniqueJobs
23
23
  entrys.each_with_object({}) { |pair, hash| hash[pair[0]] = pair[1] }
24
24
  end
25
25
 
26
+ #
27
+ # Adds a value to the sorted set
28
+ #
29
+ # @param [Array<Float, String>, String] the values to add
30
+ #
31
+ # @return [Boolean, Integer] <description>
32
+ #
33
+ def add(values)
34
+ redis do |conn|
35
+ if values.is_a?(Array)
36
+ conn.zadd(key, values)
37
+ else
38
+ conn.zadd(key, now_f, values)
39
+ end
40
+ end
41
+ end
42
+
26
43
  #
27
44
  # Return the zrak of the member
28
45
  #
@@ -45,6 +62,16 @@ module SidekiqUniqueJobs
45
62
  redis { |conn| conn.zscore(key, member) }
46
63
  end
47
64
 
65
+ #
66
+ # Clears the sorted set from all entries
67
+ #
68
+ #
69
+ # @return [Integer] number of entries removed
70
+ #
71
+ def clear
72
+ redis { |conn| conn.zremrangebyrank(key, 0, count) }
73
+ end
74
+
48
75
  #
49
76
  # Returns the count for this sorted set
50
77
  #
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ # The unique sidekiq middleware for the server processor
5
+ #
6
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
7
+ class Server
8
+ DEATH_HANDLER ||= (lambda do |job, _ex|
9
+ return unless (digest = job["lock_digest"])
10
+
11
+ SidekiqUniqueJobs::Digests.new.delete_by_digest(digest)
12
+ end).freeze
13
+ #
14
+ # Configure the server middleware
15
+ #
16
+ #
17
+ # @return [Sidekiq] the sidekiq configuration
18
+ #
19
+ def self.configure(config)
20
+ config.on(:startup) { start }
21
+ config.on(:shutdown) { stop }
22
+
23
+ return unless config.respond_to?(:death_handlers)
24
+
25
+ config.death_handlers << death_handler
26
+ end
27
+
28
+ def self.start
29
+ SidekiqUniqueJobs::UpdateVersion.call
30
+ SidekiqUniqueJobs::UpgradeLocks.call
31
+ SidekiqUniqueJobs::Orphans::Manager.start
32
+ end
33
+
34
+ def self.stop
35
+ SidekiqUniqueJobs::Orphans::Manager.stop
36
+ end
37
+
38
+ #
39
+ # A death handler for dead jobs
40
+ #
41
+ #
42
+ # @return [lambda]
43
+ #
44
+ def self.death_handler
45
+ DEATH_HANDLER
46
+ end
47
+ end
48
+ end
@@ -168,7 +168,7 @@ module SidekiqUniqueJobs
168
168
  # @option options [Integer] :lock_timeout (default is 0)
169
169
  # @option options [Integer] :lock_ttl (default is 0)
170
170
  # @option options [true,false] :enabled (default is true)
171
- # @option options [String] :unique_prefix (default is 'uniquejobs')
171
+ # @option options [String] :lock_prefix (default is 'uniquejobs')
172
172
  # @option options [Logger] :logger (default is Sidekiq.logger)
173
173
  # @yield control to the caller when given block
174
174
  def configure(options = {})
@@ -50,7 +50,7 @@ module SidekiqUniqueJobs
50
50
  # @return [Sidekiq::Worker]
51
51
  def worker_class_constantize(klazz = @worker_class)
52
52
  return klazz.class if klazz.is_a?(Sidekiq::Worker) # sidekiq v6.x
53
- return klazz unless klazz.is_a?(String)
53
+ return klazz unless klazz.is_a?(String)
54
54
 
55
55
  Object.const_get(klazz)
56
56
  rescue NameError => ex
@@ -93,7 +93,8 @@ module Sidekiq
93
93
  #
94
94
  def clear_all
95
95
  super
96
- SidekiqUniqueJobs::Digests.new.del(pattern: "*", count: 1_000)
96
+
97
+ SidekiqUniqueJobs::Digests.new.delete_by_pattern("*", count: 10_000)
97
98
  end
98
99
  end
99
100
 
@@ -3,5 +3,5 @@
3
3
  module SidekiqUniqueJobs
4
4
  #
5
5
  # @return [String] the current SidekiqUniqueJobs version
6
- VERSION = "7.0.0.beta26"
6
+ VERSION = "7.0.1"
7
7
  end
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "sidekiq/web"
5
- rescue LoadError
6
- # client-only usage
7
- end
8
-
9
3
  require_relative "web/helpers"
10
4
 
11
5
  module SidekiqUniqueJobs
@@ -19,6 +13,23 @@ module SidekiqUniqueJobs
19
13
  include Web::Helpers
20
14
  end
21
15
 
16
+ app.get "/changelogs" do
17
+ @filter = params[:filter] || "*"
18
+ @filter = "*" if @filter == ""
19
+ @count = (params[:count] || 100).to_i
20
+ @current_cursor = params[:cursor]
21
+ @prev_cursor = params[:prev_cursor]
22
+ @pagination = { pattern: @filter, cursor: @current_cursor, page_size: @count }
23
+ @total_size, @next_cursor, @changelogs = changelog.page(**@pagination)
24
+
25
+ erb(unique_template(:changelogs))
26
+ end
27
+
28
+ app.get "/changelogs/delete_all" do
29
+ changelog.clear
30
+ redirect_to :changelogs
31
+ end
32
+
22
33
  app.get "/locks" do
23
34
  @filter = params[:filter] || "*"
24
35
  @filter = "*" if @filter == ""
@@ -59,8 +70,14 @@ module SidekiqUniqueJobs
59
70
  end
60
71
  end
61
72
 
62
- if defined?(Sidekiq::Web)
63
- Sidekiq::Web.register SidekiqUniqueJobs::Web
64
- Sidekiq::Web.tabs["Locks"] = "locks"
73
+ begin
74
+ require "delegate" unless defined?(DelegateClass)
75
+ require "sidekiq/web" unless defined?(Sidekiq::Web)
76
+
77
+ Sidekiq::Web.register(SidekiqUniqueJobs::Web)
78
+ Sidekiq::Web.tabs["Locks"] = "locks"
79
+ Sidekiq::Web.tabs["Changelogs"] = "changelogs"
65
80
  Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "locales")
81
+ rescue NameError, LoadError => ex
82
+ SidekiqUniqueJobs.logger.error(ex)
66
83
  end
@@ -10,12 +10,12 @@ module SidekiqUniqueJobs
10
10
  module Helpers
11
11
  #
12
12
  # @return [String] the path to gem specific views
13
- VIEW_PATH = File.expand_path("../web/views", __dir__)
13
+ VIEW_PATH = File.expand_path("../web/views", __dir__).freeze
14
14
  #
15
15
  # @return [Array<String>] safe params
16
16
  SAFE_CPARAMS = %w[cursor prev_cursor].freeze
17
17
 
18
- module_function
18
+ extend self
19
19
 
20
20
  #
21
21
  # Opens a template file contained within this gem
@@ -25,7 +25,18 @@ module SidekiqUniqueJobs
25
25
  # @return [String] the file contents of the template
26
26
  #
27
27
  def unique_template(name)
28
- File.open(File.join(VIEW_PATH, "#{name}.erb")).read
28
+ File.open(unique_filename(name)).read
29
+ end
30
+
31
+ #
32
+ # Construct template file name
33
+ #
34
+ # @param [Symbol] name the name of the template
35
+ #
36
+ # @return [String] the full name of the file
37
+ #
38
+ def unique_filename(name)
39
+ File.join(VIEW_PATH, "#{name}.erb")
29
40
  end
30
41
 
31
42
  #
@@ -38,6 +49,16 @@ module SidekiqUniqueJobs
38
49
  @digests ||= SidekiqUniqueJobs::Digests.new
39
50
  end
40
51
 
52
+ #
53
+ # The collection of changelog entries
54
+ #
55
+ #
56
+ # @return [SidekiqUniqueJobs::Digests] the sorted set with digests
57
+ #
58
+ def changelog
59
+ @changelog ||= SidekiqUniqueJobs::Changelog.new
60
+ end
61
+
41
62
  #
42
63
  # Creates url safe parameters
43
64
  #
@@ -0,0 +1,54 @@
1
+ <header class="row">
2
+ <div class="col-sm-5">
3
+ <h3>
4
+ <%= t('Changelog Entries') %>
5
+ </h3>
6
+ </div>
7
+ <form action="<%= root_path %>changelogs" class="form form-inline" method="get">
8
+ <%= csrf_tag %>
9
+ <input name="filter" class="form-control" type="text" value="<%= @filter %>" />
10
+ <button class="btn btn-default" type="submit">
11
+ <%= t('Filter') %>
12
+ </button>
13
+ </form>
14
+ <% if @changelogs.any? && @total_size > @count.to_i %>
15
+ <div class="col-sm-4">
16
+ <%= erb unique_template(:_paging), locals: { url: "#{root_path}changelogs" } %>
17
+ </div>
18
+ <% end %>
19
+ </header>
20
+ <% if @changelogs.any? %>
21
+ <div class="table_container">
22
+ <form action="<%= root_path %>changelogs/delete_all" method="get">
23
+ <input class="btn btn-danger btn-xs" type="submit" name="delete_all" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
24
+ </form>
25
+ <br/>
26
+ <table class="table table-striped table-bordered table-hover">
27
+ <thead>
28
+ <tr>
29
+ <th><%= t('Time') %></th>
30
+ <th><%= t('Digest') %></th>
31
+ <th><%= t('Script') %></th>
32
+ <th><%= t('JID') %></th>
33
+ <th><%= t('Prev JID') %></th>
34
+ <th><%= t('Message') %></th>
35
+ </tr>
36
+ </thead>
37
+ <tbody>
38
+ <% @changelogs.each do |changelog| %>
39
+ <tr>
40
+ <td><%= safe_relative_time(changelog["time"]) %></td>
41
+ <td><%= changelog["digest"] %></td>
42
+ <td><%= changelog["script"] %></td>
43
+ <td><%= changelog["job_id"] %></td>
44
+ <td><%= changelog["prev_jid"] %></td>
45
+ <td><%= changelog["message"] %></th>
46
+ </tr>
47
+ <% end %>
48
+ </tbody>
49
+ </table>
50
+ <form action="<%= root_path %>changelogs/delete_all" method="get">
51
+ <input class="btn btn-danger btn-xs" type="submit" name="delete_all" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
52
+ </form>
53
+ </div>
54
+ <% end %>
@@ -32,7 +32,7 @@
32
32
  <% @locks.each do |lock| %>
33
33
  <tr>
34
34
  <td>
35
- <form action="<%= root_path %>locks/<%= lock.key %>" method="get">
35
+ <form action="<%= root_path %>locks/<%= lock.key %>/delete" method="get">
36
36
  <%= csrf_tag %>
37
37
  <input name="lock" value="<%= h lock.key %>" type="hidden" />
38
38
  <input class="btn btn-danger btn-xs" type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSure') %>" />
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-unique-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0.beta26
4
+ version: 7.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-28 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: brpoplpush-redis_script
@@ -56,7 +56,7 @@ dependencies:
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: '4.0'
59
+ version: '5.0'
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
62
  version: '7.0'
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '4.0'
69
+ version: '5.0'
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
72
  version: '7.0'
@@ -177,7 +177,6 @@ files:
177
177
  - lib/sidekiq_unique_jobs/orphans/observer.rb
178
178
  - lib/sidekiq_unique_jobs/orphans/reaper.rb
179
179
  - lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb
180
- - lib/sidekiq_unique_jobs/profiler.rb
181
180
  - lib/sidekiq_unique_jobs/redis.rb
182
181
  - lib/sidekiq_unique_jobs/redis/entity.rb
183
182
  - lib/sidekiq_unique_jobs/redis/hash.rb
@@ -189,6 +188,7 @@ files:
189
188
  - lib/sidekiq_unique_jobs/rspec/matchers/have_valid_sidekiq_options.rb
190
189
  - lib/sidekiq_unique_jobs/script.rb
191
190
  - lib/sidekiq_unique_jobs/script/caller.rb
191
+ - lib/sidekiq_unique_jobs/server.rb
192
192
  - lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb
193
193
  - lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb
194
194
  - lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb
@@ -202,6 +202,7 @@ files:
202
202
  - lib/sidekiq_unique_jobs/web.rb
203
203
  - lib/sidekiq_unique_jobs/web/helpers.rb
204
204
  - lib/sidekiq_unique_jobs/web/views/_paging.erb
205
+ - lib/sidekiq_unique_jobs/web/views/changelogs.erb
205
206
  - lib/sidekiq_unique_jobs/web/views/lock.erb
206
207
  - lib/sidekiq_unique_jobs/web/views/locks.erb
207
208
  - lib/tasks/changelog.rake
@@ -215,7 +216,22 @@ metadata:
215
216
  source_code_uri: https://github.com/mhenrixon/sidekiq-unique-jobs
216
217
  changelog_uri: https://github.com/mhenrixon/sidekiq-unique-jobs/blob/master/CHANGELOG.md
217
218
  post_install_message: |
218
- This version deprecated the configuration options:
219
+ IMPORTANT!
220
+
221
+ Automatic configuration of the sidekiq middelware is no longer done.
222
+ Please see: https://github.com/mhenrixon/sidekiq-unique-jobs/blob/master/README.md#add-the-middleware
223
+
224
+ This version deprecated the following sidekiq_options
225
+
226
+ - sidekiq_options lock_args: :method_name
227
+
228
+ It is now configured with:
229
+
230
+ - sidekiq_options lock_args_method: :method_name
231
+
232
+ This is also true for `Sidekiq.default_worker_options`
233
+
234
+ We also deprecated the global configuration options:
219
235
  - default_lock_ttl
220
236
  - default_lock_ttl=
221
237
  - default_lock_timeout
@@ -236,11 +252,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
236
252
  version: 2.5.0
237
253
  required_rubygems_version: !ruby/object:Gem::Requirement
238
254
  requirements:
239
- - - ">"
255
+ - - ">="
240
256
  - !ruby/object:Gem::Version
241
- version: 1.3.1
257
+ version: '0'
242
258
  requirements: []
243
- rubygems_version: 3.1.2
259
+ rubygems_version: 3.2.4
244
260
  signing_key:
245
261
  specification_version: 4
246
262
  summary: Sidekiq middleware that prevents duplicates jobs
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SidekiqUniqueJobs
4
- #
5
- # Class MethodProfiler provides method level profiling
6
- #
7
- # @author Mikael Henriksson <mikael@mhenrixon.com>
8
- #
9
- class Profiler
10
- def self.patch(klass, methods, name) # rubocop:disable Metrics/MethodLength
11
- patches = methods.map do |method_name|
12
- <<~RUBY
13
- unless defined?(#{method_name}__mp_unpatched)
14
- alias_method :#{method_name}__mp_unpatched, :#{method_name}
15
- def #{method_name}(*args, &blk)
16
- unless prof = Thread.current[:_method_profiler]
17
- return #{method_name}__mp_unpatched(*args, &blk)
18
- end
19
- begin
20
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
21
- #{method_name}__mp_unpatched(*args, &blk)
22
- ensure
23
- data = (prof[:#{name}] ||= {duration: 0.0, calls: 0})
24
- data[:duration] += Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
25
- data[:calls] += 1
26
- end
27
- end
28
- end
29
- RUBY
30
- end.join("\n")
31
-
32
- klass.class_eval patches
33
- end
34
-
35
- def self.start
36
- Thread.current[:_method_profiler] = {
37
- __start: current_timestamp,
38
- }
39
- end
40
-
41
- def self.stop
42
- finish = current_timestamp
43
- return unless (data = Thread.current[:_method_profiler])
44
-
45
- Thread.current[:_method_profiler] = nil
46
- start = data.delete(:__start)
47
- data[:total_duration] = finish - start
48
- data
49
- end
50
-
51
- def self.current_timestamp
52
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
53
- end
54
- end
55
- end