sidekiq-unique-jobs 7.0.2 → 7.1.12

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +331 -69
  3. data/README.md +546 -426
  4. data/lib/sidekiq_unique_jobs/changelog.rb +2 -2
  5. data/lib/sidekiq_unique_jobs/config.rb +55 -4
  6. data/lib/sidekiq_unique_jobs/constants.rb +44 -45
  7. data/lib/sidekiq_unique_jobs/deprecation.rb +65 -0
  8. data/lib/sidekiq_unique_jobs/digests.rb +5 -8
  9. data/lib/sidekiq_unique_jobs/exceptions.rb +10 -0
  10. data/lib/sidekiq_unique_jobs/json.rb +7 -0
  11. data/lib/sidekiq_unique_jobs/lock/base_lock.rb +64 -51
  12. data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +37 -9
  13. data/lib/sidekiq_unique_jobs/lock/until_executed.rb +23 -5
  14. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +21 -1
  15. data/lib/sidekiq_unique_jobs/lock/until_expired.rb +27 -0
  16. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +15 -8
  17. data/lib/sidekiq_unique_jobs/lock_config.rb +8 -4
  18. data/lib/sidekiq_unique_jobs/lock_ttl.rb +1 -1
  19. data/lib/sidekiq_unique_jobs/locksmith.rb +93 -80
  20. data/lib/sidekiq_unique_jobs/logging.rb +40 -11
  21. data/lib/sidekiq_unique_jobs/lua/lock.lua +3 -3
  22. data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_process_set.lua +1 -1
  23. data/lib/sidekiq_unique_jobs/lua/unlock.lua +12 -5
  24. data/lib/sidekiq_unique_jobs/middleware/client.rb +8 -10
  25. data/lib/sidekiq_unique_jobs/middleware/server.rb +2 -0
  26. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +7 -3
  27. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +2 -13
  28. data/lib/sidekiq_unique_jobs/orphans/manager.rb +49 -3
  29. data/lib/sidekiq_unique_jobs/orphans/reaper_resurrector.rb +170 -0
  30. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +38 -8
  31. data/lib/sidekiq_unique_jobs/redis/entity.rb +7 -1
  32. data/lib/sidekiq_unique_jobs/redis/sorted_set.rb +1 -1
  33. data/lib/sidekiq_unique_jobs/reflectable.rb +26 -0
  34. data/lib/sidekiq_unique_jobs/reflections.rb +79 -0
  35. data/lib/sidekiq_unique_jobs/script/caller.rb +3 -1
  36. data/lib/sidekiq_unique_jobs/server.rb +14 -1
  37. data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +35 -13
  38. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +57 -2
  39. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +1 -11
  40. data/lib/sidekiq_unique_jobs/timer_task.rb +78 -0
  41. data/lib/sidekiq_unique_jobs/timing.rb +1 -1
  42. data/lib/sidekiq_unique_jobs/version.rb +1 -1
  43. data/lib/sidekiq_unique_jobs/web/helpers.rb +5 -5
  44. data/lib/sidekiq_unique_jobs/web/views/_paging.erb +4 -4
  45. data/lib/sidekiq_unique_jobs/web/views/changelogs.erb +1 -1
  46. data/lib/sidekiq_unique_jobs/web/views/locks.erb +17 -15
  47. data/lib/sidekiq_unique_jobs/web.rb +11 -4
  48. data/lib/sidekiq_unique_jobs.rb +7 -1
  49. data/lib/tasks/changelog.rake +15 -15
  50. metadata +17 -16
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ # @see [Concurrent::TimerTask] https://www.rubydoc.info/gems/concurrent-ruby/Concurrent/TimerTask
5
+ #
6
+ class TimerTask < ::Concurrent::TimerTask
7
+ private
8
+
9
+ def ns_initialize(opts, &task)
10
+ set_deref_options(opts)
11
+
12
+ self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
13
+ self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
14
+ @run_now = opts[:now] || opts[:run_now]
15
+ @executor = Concurrent::RubySingleThreadExecutor.new
16
+ @running = Concurrent::AtomicBoolean.new(false)
17
+ @task = task
18
+ @value = nil
19
+
20
+ self.observers = Concurrent::Collection::CopyOnNotifyObserverSet.new
21
+ end
22
+
23
+ def schedule_next_task(interval = execution_interval)
24
+ exec_task = ->(completion) { execute_task(completion) }
25
+ Concurrent::ScheduledTask.execute(interval, args: [Concurrent::Event.new], &exec_task)
26
+ nil
27
+ end
28
+
29
+ # @!visibility private
30
+ def execute_task(completion) # rubocop:disable Metrics/MethodLength
31
+ return nil unless @running.true?
32
+
33
+ timeout_task = -> { timeout_task(completion) }
34
+
35
+ Concurrent::ScheduledTask.execute(
36
+ timeout_interval,
37
+ args: [completion],
38
+ &timeout_task
39
+ )
40
+ @thread_completed = Concurrent::Event.new
41
+
42
+ @value = @reason = nil
43
+ @executor.post do
44
+ @value = @task.call(self)
45
+ rescue Exception => ex # rubocop:disable Lint/RescueException
46
+ @reason = ex
47
+ ensure
48
+ @thread_completed.set
49
+ end
50
+
51
+ @thread_completed.wait
52
+
53
+ if completion.try?
54
+ schedule_next_task
55
+ time = Time.now
56
+ observers.notify_observers do
57
+ [time, value, @reason]
58
+ end
59
+ end
60
+ nil
61
+ end
62
+
63
+ # @!visibility private
64
+ def timeout_task(completion)
65
+ return unless @running.true?
66
+ return unless completion.try?
67
+
68
+ @executor.kill
69
+ @executor.wait_for_termination
70
+ @executor = Concurrent::RubySingleThreadExecutor.new
71
+
72
+ @thread_completed.set
73
+
74
+ schedule_next_task
75
+ observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new)
76
+ end
77
+ end
78
+ end
@@ -51,7 +51,7 @@ module SidekiqUniqueJobs
51
51
  if Process.const_defined?("CLOCK_MONOTONIC")
52
52
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
53
53
  else
54
- Time.now.to_f
54
+ now_f
55
55
  end
56
56
  end
57
57
  end
@@ -3,5 +3,5 @@
3
3
  module SidekiqUniqueJobs
4
4
  #
5
5
  # @return [String] the current SidekiqUniqueJobs version
6
- VERSION = "7.0.2"
6
+ VERSION = "7.1.12"
7
7
  end
@@ -13,7 +13,9 @@ module SidekiqUniqueJobs
13
13
  VIEW_PATH = File.expand_path("../web/views", __dir__).freeze
14
14
  #
15
15
  # @return [Array<String>] safe params
16
- SAFE_CPARAMS = %w[cursor prev_cursor].freeze
16
+ SAFE_CPARAMS = %w[
17
+ filter count cursor prev_cursor poll direction
18
+ ].freeze
17
19
 
18
20
  extend self
19
21
 
@@ -67,10 +69,8 @@ module SidekiqUniqueJobs
67
69
  # @return [String] a url safe parameter string
68
70
  #
69
71
  def cparams(options)
70
- # stringify
71
- options.transform_keys(&:to_s)
72
-
73
- params.merge(options).map do |key, value|
72
+ stringified_options = options.transform_keys(&:to_s)
73
+ params.merge(stringified_options).map do |key, value|
74
74
  next unless SAFE_CPARAMS.include?(key)
75
75
 
76
76
  "#{key}=#{CGI.escape(value.to_s)}"
@@ -1,10 +1,10 @@
1
1
  <ul class="pagination pull-right flip">
2
2
  <% if @prev_cursor %>
3
- <li>
4
- <a href="<%= url %>?<%= cparams(cursor: @prev_cursor, prev_cursor: @next_cursor) %>">Previous <%= @count %></a>
5
- </li>
3
+ <li>
4
+ <a href="<%= url %>?<%= cparams(filter: @filter, cursor: @prev_cursor, prev_cursor: @next_cursor) %>">Previous <%= @count %></a>
5
+ </li>
6
6
  <% end %>
7
7
  <li>
8
- <a href="<%= url %>?<%= cparams(cursor: @next_cursor, prev_cursor: @current_cursor) %>">Next <%= @count %></a>
8
+ <a href="<%= url %>?<%= cparams(filter: @filter, cursor: @next_cursor, prev_cursor: @current_cursor) %>">Next <%= @count %></a>
9
9
  </li>
10
10
  </ul>
@@ -36,7 +36,7 @@
36
36
  </thead>
37
37
  <tbody>
38
38
  <% @changelogs.each do |changelog| %>
39
- <tr>
39
+ <tr class="changelog-row">
40
40
  <td><%= safe_relative_time(changelog["time"]) %></td>
41
41
  <td><%= changelog["digest"] %></td>
42
42
  <td><%= changelog["script"] %></td>
@@ -11,7 +11,7 @@
11
11
  <%= t('Filter') %>
12
12
  </button>
13
13
  </form>
14
- <% if @locks.any? && @total_size > @count.to_i %>
14
+ <% if @locks.any? && @total_size > @count %>
15
15
  <div class="col-sm-4">
16
16
  <%= erb unique_template(:_paging), locals: { url: "#{root_path}locks" } %>
17
17
  </div>
@@ -30,20 +30,22 @@
30
30
  </tr>
31
31
  </thead>
32
32
  <% @locks.each do |lock| %>
33
- <tr>
34
- <td>
35
- <form action="<%= root_path %>locks/<%= lock.key %>/delete" method="get">
36
- <%= csrf_tag %>
37
- <input name="lock" value="<%= h lock.key %>" type="hidden" />
38
- <input class="btn btn-danger btn-xs" type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSure') %>" />
39
- </form>
40
- </td>
41
- <td><a href="<%= root_path %>locks/<%= lock.key %>"><%= lock.key %></a></td>
42
- <td><%= lock.info["lock"] %></th>
43
- <td><%= lock.locked.count %></td>
44
- <td><%= safe_relative_time(lock.created_at) %></td>
45
- </tr>
46
- <% end %>
33
+ <tbody>
34
+ <tr class="lock-row">
35
+ <td>
36
+ <form action="<%= root_path %>locks/<%= lock.key %>/delete" method="get">
37
+ <%= csrf_tag %>
38
+ <input name="lock" value="<%= h lock.key %>" type="hidden" />
39
+ <input class="btn btn-danger btn-xs" type="submit" name="delete" value="<%= t('Delete') %>" data-confirm="<%= t('AreYouSure') %>" />
40
+ </form>
41
+ </td>
42
+ <td><a href="<%= root_path %>locks/<%= lock.key %>"><%= lock.key %></a></td>
43
+ <td><%= lock.info["lock"] %></td>
44
+ <td><%= lock.locked.count %></td>
45
+ <td><%= safe_relative_time(lock.created_at) %></td>
46
+ </tr>
47
+ </tbody>
48
+ <% end %>
47
49
  </table>
48
50
  <form action="<%= root_path %>locks/delete_all" method="get">
49
51
  <input class="btn btn-danger btn-xs" type="submit" name="delete_all" value="<%= t('DeleteAll') %>" data-confirm="<%= t('AreYouSure') %>" />
@@ -19,8 +19,11 @@ module SidekiqUniqueJobs
19
19
  @count = (params[:count] || 100).to_i
20
20
  @current_cursor = params[:cursor]
21
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)
22
+ @total_size, @next_cursor, @changelogs = changelog.page(
23
+ cursor: @current_cursor,
24
+ pattern: @filter,
25
+ page_size: @count,
26
+ )
24
27
 
25
28
  erb(unique_template(:changelogs))
26
29
  end
@@ -36,8 +39,12 @@ module SidekiqUniqueJobs
36
39
  @count = (params[:count] || 100).to_i
37
40
  @current_cursor = params[:cursor]
38
41
  @prev_cursor = params[:prev_cursor]
39
- @pagination = { pattern: @filter, cursor: @current_cursor, page_size: @count }
40
- @total_size, @next_cursor, @locks = digests.page(**@pagination)
42
+
43
+ @total_size, @next_cursor, @locks = digests.page(
44
+ cursor: @current_cursor,
45
+ pattern: @filter,
46
+ page_size: @count,
47
+ )
41
48
 
42
49
  erb(unique_template(:locks))
43
50
  end
@@ -3,9 +3,10 @@
3
3
  require "brpoplpush/redis_script"
4
4
  require "concurrent/future"
5
5
  require "concurrent/promises"
6
- require "concurrent/timer_task"
7
6
  require "concurrent/map"
8
7
  require "concurrent/mutable_struct"
8
+ require "concurrent/timer_task"
9
+ require "concurrent/executor/ruby_single_thread_executor"
9
10
  require "digest"
10
11
  require "digest/sha1"
11
12
  require "erb"
@@ -14,6 +15,10 @@ require "json"
14
15
  require "pathname"
15
16
  require "sidekiq"
16
17
 
18
+ require "sidekiq_unique_jobs/deprecation"
19
+ require "sidekiq_unique_jobs/reflections"
20
+ require "sidekiq_unique_jobs/reflectable"
21
+ require "sidekiq_unique_jobs/timer_task"
17
22
  require "sidekiq_unique_jobs/version"
18
23
  require "sidekiq_unique_jobs/version_check"
19
24
  require "sidekiq_unique_jobs/constants"
@@ -39,6 +44,7 @@ require "sidekiq_unique_jobs/batch_delete"
39
44
  require "sidekiq_unique_jobs/orphans/reaper"
40
45
  require "sidekiq_unique_jobs/orphans/observer"
41
46
  require "sidekiq_unique_jobs/orphans/manager"
47
+ require "sidekiq_unique_jobs/orphans/reaper_resurrector"
42
48
  require "sidekiq_unique_jobs/cli"
43
49
  require "sidekiq_unique_jobs/core_ext"
44
50
  require "sidekiq_unique_jobs/lock_timeout"
@@ -1,22 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Style/MutableConstant
4
+ CHANGELOG_CMD = %w[
5
+ github_changelog_generator
6
+ --no-verbose
7
+ --user
8
+ mhenrixon
9
+ --project
10
+ sidekiq-unique-jobs
11
+ --token
12
+ ]
13
+ ADD_CHANGELOG_CMD = "git add --all"
14
+ COMMIT_CHANGELOG_CMD = "git commit -a -m 'Update changelog'"
15
+ # rubocop:enable Style/MutableConstant
16
+
3
17
  desc "Generate a Changelog"
4
18
  task :changelog do
5
- # rubocop:disable Style/MutableConstant
6
- CHANGELOG_CMD ||= %w[
7
- github_changelog_generator
8
- --no-verbose
9
- --user
10
- mhenrixon
11
- --project
12
- sidekiq-unique-jobs
13
- --token
14
- ]
15
- ADD_CHANGELOG_CMD ||= "git add --all"
16
- COMMIT_CHANGELOG_CMD ||= "git commit -a -m 'Update changelog'"
17
- # rubocop:enable Style/MutableConstant
18
-
19
- sh("git checkout master")
19
+ sh("git checkout main")
20
20
  sh(*CHANGELOG_CMD.push(ENV["CHANGELOG_GITHUB_TOKEN"]))
21
21
  sh(ADD_CHANGELOG_CMD)
22
22
  sh(COMMIT_CHANGELOG_CMD)
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.2
4
+ version: 7.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-08 00:00:00.000000000 Z
11
+ date: 2021-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: brpoplpush-redis_script
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.0
19
+ version: 0.1.1
20
20
  - - "<="
21
21
  - !ruby/object:Gem::Version
22
22
  version: 2.0.0
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">"
28
28
  - !ruby/object:Gem::Version
29
- version: 0.0.0
29
+ version: 0.1.1
30
30
  - - "<="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 2.0.0
@@ -59,7 +59,7 @@ dependencies:
59
59
  version: '5.0'
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
- version: '7.0'
62
+ version: '8.0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
@@ -69,7 +69,7 @@ dependencies:
69
69
  version: '5.0'
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
- version: '7.0'
72
+ version: '8.0'
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: thor
75
75
  requirement: !ruby/object:Gem::Requirement
@@ -79,7 +79,7 @@ dependencies:
79
79
  version: '0.20'
80
80
  - - "<"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.0'
82
+ version: '3.0'
83
83
  type: :runtime
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
@@ -89,7 +89,7 @@ dependencies:
89
89
  version: '0.20'
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
- version: '2.0'
92
+ version: '3.0'
93
93
  description: |
94
94
  Prevents simultaneous Sidekiq jobs with the same unique arguments to run.
95
95
  Highly configurable to suite your specific needs.
@@ -113,6 +113,7 @@ files:
113
113
  - lib/sidekiq_unique_jobs/connection.rb
114
114
  - lib/sidekiq_unique_jobs/constants.rb
115
115
  - lib/sidekiq_unique_jobs/core_ext.rb
116
+ - lib/sidekiq_unique_jobs/deprecation.rb
116
117
  - lib/sidekiq_unique_jobs/digests.rb
117
118
  - lib/sidekiq_unique_jobs/exceptions.rb
118
119
  - lib/sidekiq_unique_jobs/job.rb
@@ -176,6 +177,7 @@ files:
176
177
  - lib/sidekiq_unique_jobs/orphans/null_reaper.rb
177
178
  - lib/sidekiq_unique_jobs/orphans/observer.rb
178
179
  - lib/sidekiq_unique_jobs/orphans/reaper.rb
180
+ - lib/sidekiq_unique_jobs/orphans/reaper_resurrector.rb
179
181
  - lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb
180
182
  - lib/sidekiq_unique_jobs/redis.rb
181
183
  - lib/sidekiq_unique_jobs/redis/entity.rb
@@ -184,6 +186,8 @@ files:
184
186
  - lib/sidekiq_unique_jobs/redis/set.rb
185
187
  - lib/sidekiq_unique_jobs/redis/sorted_set.rb
186
188
  - lib/sidekiq_unique_jobs/redis/string.rb
189
+ - lib/sidekiq_unique_jobs/reflectable.rb
190
+ - lib/sidekiq_unique_jobs/reflections.rb
187
191
  - lib/sidekiq_unique_jobs/rspec/matchers.rb
188
192
  - lib/sidekiq_unique_jobs/rspec/matchers/have_valid_sidekiq_options.rb
189
193
  - lib/sidekiq_unique_jobs/script.rb
@@ -193,6 +197,7 @@ files:
193
197
  - lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb
194
198
  - lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb
195
199
  - lib/sidekiq_unique_jobs/testing.rb
200
+ - lib/sidekiq_unique_jobs/timer_task.rb
196
201
  - lib/sidekiq_unique_jobs/timing.rb
197
202
  - lib/sidekiq_unique_jobs/unlockable.rb
198
203
  - lib/sidekiq_unique_jobs/update_version.rb
@@ -210,15 +215,11 @@ homepage: https://mhenrixon.github.io/sidekiq-unique-jobs
210
215
  licenses:
211
216
  - MIT
212
217
  metadata:
213
- homepage_uri: https://mhenrixon.github.io/sidekiq-unique-jobs
214
- bug_tracker_uri: https://github.com/mhenrixon/sidekiq-unique-jobs/issues
215
- documentation_uri: https://mhenrixon.github.io/sidekiq-unique-jobs
216
- source_code_uri: https://github.com/mhenrixon/sidekiq-unique-jobs
217
- changelog_uri: https://github.com/mhenrixon/sidekiq-unique-jobs/blob/master/CHANGELOG.md
218
+ rubygems_mfa_required: 'true'
218
219
  post_install_message: |
219
220
  IMPORTANT!
220
221
 
221
- Automatic configuration of the sidekiq middelware is no longer done.
222
+ Automatic configuration of the sidekiq middleware is no longer done.
222
223
  Please see: https://github.com/mhenrixon/sidekiq-unique-jobs/blob/master/README.md#add-the-middleware
223
224
 
224
225
  This version deprecated the following sidekiq_options
@@ -249,14 +250,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
249
250
  requirements:
250
251
  - - ">="
251
252
  - !ruby/object:Gem::Version
252
- version: 2.5.0
253
+ version: '2.5'
253
254
  required_rubygems_version: !ruby/object:Gem::Requirement
254
255
  requirements:
255
256
  - - ">="
256
257
  - !ruby/object:Gem::Version
257
258
  version: '0'
258
259
  requirements: []
259
- rubygems_version: 3.2.6
260
+ rubygems_version: 3.2.32
260
261
  signing_key:
261
262
  specification_version: 4
262
263
  summary: Sidekiq middleware that prevents duplicates jobs