sidekiq-unique-jobs 7.0.0.beta27 → 7.0.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +90 -14
- data/README.md +162 -30
- data/lib/sidekiq-unique-jobs.rb +0 -2
- data/lib/sidekiq_unique_jobs.rb +1 -0
- data/lib/sidekiq_unique_jobs/batch_delete.rb +1 -1
- data/lib/sidekiq_unique_jobs/changelog.rb +11 -4
- data/lib/sidekiq_unique_jobs/config.rb +2 -2
- data/lib/sidekiq_unique_jobs/constants.rb +2 -0
- data/lib/sidekiq_unique_jobs/digests.rb +1 -1
- data/lib/sidekiq_unique_jobs/job.rb +1 -1
- data/lib/sidekiq_unique_jobs/json.rb +7 -1
- data/lib/sidekiq_unique_jobs/lock.rb +31 -1
- data/lib/sidekiq_unique_jobs/lock/while_executing.rb +1 -1
- data/lib/sidekiq_unique_jobs/lock_config.rb +2 -0
- data/lib/sidekiq_unique_jobs/locksmith.rb +1 -1
- data/lib/sidekiq_unique_jobs/lua/lock.lua +10 -11
- data/lib/sidekiq_unique_jobs/lua/reap_orphans.lua +8 -7
- data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_process_set.lua +9 -2
- data/lib/sidekiq_unique_jobs/middleware.rb +0 -57
- data/lib/sidekiq_unique_jobs/on_conflict/replace.rb +9 -8
- data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +1 -1
- data/lib/sidekiq_unique_jobs/orphans/lua_reaper.rb +1 -1
- data/lib/sidekiq_unique_jobs/orphans/reaper.rb +10 -0
- data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +14 -5
- data/lib/sidekiq_unique_jobs/redis/entity.rb +9 -3
- data/lib/sidekiq_unique_jobs/redis/sorted_set.rb +27 -0
- data/lib/sidekiq_unique_jobs/server.rb +48 -0
- data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +1 -1
- data/lib/sidekiq_unique_jobs/version.rb +1 -1
- data/lib/sidekiq_unique_jobs/web.rb +26 -9
- data/lib/sidekiq_unique_jobs/web/helpers.rb +24 -3
- data/lib/sidekiq_unique_jobs/web/views/changelogs.erb +54 -0
- data/lib/sidekiq_unique_jobs/web/views/locks.erb +1 -1
- metadata +12 -8
- data/lib/sidekiq_unique_jobs/profiler.rb +0 -55
@@ -76,6 +76,16 @@ module SidekiqUniqueJobs
|
|
76
76
|
config.reaper
|
77
77
|
end
|
78
78
|
|
79
|
+
#
|
80
|
+
# The configured timeout for the reaper
|
81
|
+
#
|
82
|
+
#
|
83
|
+
# @return [Integer] timeout in seconds
|
84
|
+
#
|
85
|
+
def reaper_timeout
|
86
|
+
config.reaper_timeout
|
87
|
+
end
|
88
|
+
|
79
89
|
#
|
80
90
|
# The number of locks to reap at a time
|
81
91
|
#
|
@@ -52,11 +52,11 @@ module SidekiqUniqueJobs
|
|
52
52
|
# @return [Array<String>] an array of orphaned digests
|
53
53
|
#
|
54
54
|
def orphans
|
55
|
-
conn.zrevrange(digests.key, 0, -1).each_with_object([]) do |digest,
|
55
|
+
conn.zrevrange(digests.key, 0, -1).each_with_object([]) do |digest, memo|
|
56
56
|
next if belongs_to_job?(digest)
|
57
57
|
|
58
|
-
|
59
|
-
break if
|
58
|
+
memo << digest
|
59
|
+
break if memo.size >= reaper_count
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -117,7 +117,7 @@ module SidekiqUniqueJobs
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
def active?(digest) # rubocop:disable Metrics/MethodLength
|
120
|
+
def active?(digest) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
121
121
|
Sidekiq.redis do |conn|
|
122
122
|
procs = conn.sscan_each("processes").to_a
|
123
123
|
return false if procs.empty?
|
@@ -132,7 +132,12 @@ module SidekiqUniqueJobs
|
|
132
132
|
next unless workers.any?
|
133
133
|
|
134
134
|
workers.each_pair do |_tid, job|
|
135
|
-
|
135
|
+
next unless (item = safe_load_json(job))
|
136
|
+
|
137
|
+
payload = safe_load_json(item[PAYLOAD])
|
138
|
+
|
139
|
+
return true if payload[LOCK_DIGEST] == digest
|
140
|
+
return true if considered_active?(payload[CREATED_AT])
|
136
141
|
end
|
137
142
|
end
|
138
143
|
|
@@ -140,6 +145,10 @@ module SidekiqUniqueJobs
|
|
140
145
|
end
|
141
146
|
end
|
142
147
|
|
148
|
+
def considered_active?(time_f)
|
149
|
+
(Time.now - reaper_timeout).to_f < time_f
|
150
|
+
end
|
151
|
+
|
143
152
|
#
|
144
153
|
# Loops through all the redis queues and yields them one by one
|
145
154
|
#
|
@@ -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
|
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] :
|
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 = {})
|
@@ -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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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(
|
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
|
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.
|
4
|
+
version: 7.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikael Henriksson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-08 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: '
|
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: '
|
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
|
@@ -217,6 +218,9 @@ metadata:
|
|
217
218
|
post_install_message: |
|
218
219
|
IMPORTANT!
|
219
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
|
+
|
220
224
|
This version deprecated the following sidekiq_options
|
221
225
|
|
222
226
|
- sidekiq_options lock_args: :method_name
|
@@ -248,11 +252,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
248
252
|
version: 2.5.0
|
249
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
254
|
requirements:
|
251
|
-
- - "
|
255
|
+
- - ">="
|
252
256
|
- !ruby/object:Gem::Version
|
253
|
-
version:
|
257
|
+
version: '0'
|
254
258
|
requirements: []
|
255
|
-
rubygems_version: 3.
|
259
|
+
rubygems_version: 3.2.6
|
256
260
|
signing_key:
|
257
261
|
specification_version: 4
|
258
262
|
summary: Sidekiq middleware that prevents duplicates jobs
|