sidekiq-unique-jobs 6.0.10 → 6.0.11
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/.travis.yml +4 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +1 -0
- data/README.md +4 -6
- data/lib/sidekiq_unique_jobs/client/middleware.rb +1 -1
- data/lib/sidekiq_unique_jobs/locksmith.rb +23 -23
- data/lib/sidekiq_unique_jobs/logging.rb +5 -1
- data/lib/sidekiq_unique_jobs/server/middleware.rb +1 -1
- data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +9 -0
- data/lib/sidekiq_unique_jobs/version.rb +1 -1
- data/redis/convert_legacy_lock.lua +21 -0
- data/redis/lock.lua +13 -10
- data/redis/unlock.lua +10 -9
- data/sidekiq-unique-jobs.gemspec +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4794cab4e8c46ab8a1c2f8d3f1f4a0e40eee2f5c0a78c1750816a4f08298fb3e
|
4
|
+
data.tar.gz: 5542da14289cd0287001c997b439f77445c9d7b7c13cc8307801a55012217a7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee3cddb22fa61d68e5b209fbd129c5e8c1c88c3cb02feae0f1d0b869d3722ab9f8e5d08cf0a2d0bbcbb11be2205ee35e5f9202c24eb56cae360e79e4bacd54c9
|
7
|
+
data.tar.gz: e0c980ae65ac375cf0de4595b61ca4137c52ba0335d947560d7d7550f71db8873a4dca228e18f3319c3cdd551b7377a262133c1d7b66ad8daf9a8143b3fdd4f2
|
data/.travis.yml
CHANGED
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v6.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.10) (2019-02-23)
|
4
|
+
[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.9...v6.0.10)
|
5
|
+
|
6
|
+
**Closed issues:**
|
7
|
+
|
8
|
+
- Unsure of sane defaults [\#372](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/372)
|
9
|
+
|
10
|
+
**Merged pull requests:**
|
11
|
+
|
12
|
+
- Log job silently complete [\#371](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/371) ([tadejm](https://github.com/tadejm))
|
13
|
+
|
3
14
|
## [v6.0.9](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.9) (2019-02-11)
|
4
15
|
[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.8...v6.0.9)
|
5
16
|
|
data/Gemfile
CHANGED
@@ -7,6 +7,7 @@ gem "appraisal", "~> 2.2.0"
|
|
7
7
|
gem "rspec-eventually", require: false
|
8
8
|
gem "rspec-its", require: false
|
9
9
|
gem "rspec-retry", require: false
|
10
|
+
gem "sidekiq", git: "https://github.com/mperham/sidekiq.git", branch: "6-0"
|
10
11
|
|
11
12
|
platforms :mri_25 do
|
12
13
|
gem "benchmark-ips"
|
data/README.md
CHANGED
@@ -94,15 +94,13 @@ See [Locking & Unlocking](https://github.com/mhenrixon/sidekiq-unique-jobs/wiki/
|
|
94
94
|
|
95
95
|
### Lock Expiration
|
96
96
|
|
97
|
-
|
97
|
+
Lock expiration is used for two things. For the `UntilExpired` job releases the lock upon expiry. This is done from the client.
|
98
98
|
|
99
|
-
Since
|
100
|
-
|
101
|
-
In previous versions there was a default expiration of 30 minutes which didn't work for a lot of long running jobs. Since version 6 there will be no expiration of any jobs from the default configuration. Please don't use `lock_expiration` unless you really know what you are doing.
|
99
|
+
Since v6.0.11 the other locks will expire after the server is done processing.
|
102
100
|
|
103
101
|
```ruby
|
104
102
|
sidekiq_options lock_expiration: nil # default - don't expire keys
|
105
|
-
sidekiq_options lock_expiration: 20.days # expire this lock in 20 days
|
103
|
+
sidekiq_options lock_expiration: 20.days.to_i # expire this lock in 20 days
|
106
104
|
```
|
107
105
|
|
108
106
|
### Lock Timeout
|
@@ -363,7 +361,7 @@ end
|
|
363
361
|
|
364
362
|
### Cleanup Dead Locks
|
365
363
|
|
366
|
-
For sidekiq versions before 5.1 a `sidekiq_retries_exhausted` block is required per worker class.
|
364
|
+
For sidekiq versions before 5.1 a `sidekiq_retries_exhausted` block is required per worker class. This is deprecated in Sidekiq 6.0
|
367
365
|
|
368
366
|
```ruby
|
369
367
|
class MyWorker
|
@@ -39,7 +39,7 @@ module SidekiqUniqueJobs
|
|
39
39
|
|
40
40
|
def locked?
|
41
41
|
SidekiqUniqueJobs::Job.add_uniqueness(item)
|
42
|
-
|
42
|
+
SidekiqUniqueJobs.with_context(logging_context(self.class, item)) do
|
43
43
|
locked = lock.lock
|
44
44
|
warn_about_duplicate unless locked
|
45
45
|
locked
|
@@ -4,6 +4,7 @@ module SidekiqUniqueJobs
|
|
4
4
|
# Lock manager class that handles all the various locks
|
5
5
|
#
|
6
6
|
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# rubocop:disable ClassLength
|
7
8
|
class Locksmith
|
8
9
|
include SidekiqUniqueJobs::Connection
|
9
10
|
|
@@ -13,35 +14,23 @@ module SidekiqUniqueJobs
|
|
13
14
|
# @option item [String] :unique_digest the unique digest (See: {UniqueArgs#unique_digest})
|
14
15
|
# @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
|
15
16
|
def initialize(item, redis_pool = nil)
|
16
|
-
@concurrency = 1 # removed in a0cff5bc42edbe7190d6ede7e7f845074d2d7af6
|
17
|
-
@
|
17
|
+
# @concurrency = 1 # removed in a0cff5bc42edbe7190d6ede7e7f845074d2d7af6
|
18
|
+
@ttl = item[LOCK_EXPIRATION_KEY]
|
18
19
|
@jid = item[JID_KEY]
|
19
20
|
@unique_digest = item[UNIQUE_DIGEST_KEY]
|
21
|
+
@lock_type = item[LOCK_KEY]
|
22
|
+
@lock_type &&= @lock_type.to_sym
|
20
23
|
@redis_pool = redis_pool
|
21
24
|
end
|
22
25
|
|
23
|
-
#
|
24
|
-
# @return [true, false]
|
25
|
-
def exists?
|
26
|
-
redis(redis_pool) { |conn| conn.exists(exists_key) }
|
27
|
-
end
|
28
|
-
|
29
|
-
# The number of available resourced for this lock
|
30
|
-
# @return [Integer] the number of available resources
|
31
|
-
def available_count
|
32
|
-
return concurrency unless exists?
|
33
|
-
|
34
|
-
redis(redis_pool) { |conn| conn.llen(available_key) }
|
35
|
-
end
|
36
|
-
|
37
|
-
# Deletes the lock unless it has an expiration set
|
26
|
+
# Deletes the lock unless it has a ttl set
|
38
27
|
def delete
|
39
|
-
return if
|
28
|
+
return if ttl
|
40
29
|
|
41
30
|
delete!
|
42
31
|
end
|
43
32
|
|
44
|
-
# Deletes the lock regardless of if it has
|
33
|
+
# Deletes the lock regardless of if it has a ttl set
|
45
34
|
def delete!
|
46
35
|
Scripts.call(
|
47
36
|
:delete,
|
@@ -58,7 +47,7 @@ module SidekiqUniqueJobs
|
|
58
47
|
def lock(timeout = nil, &block)
|
59
48
|
Scripts.call(:lock, redis_pool,
|
60
49
|
keys: [exists_key, grabbed_key, available_key, UNIQUE_SET, unique_digest],
|
61
|
-
argv: [jid,
|
50
|
+
argv: [jid, ttl, lock_type])
|
62
51
|
|
63
52
|
grab_token(timeout) do |token|
|
64
53
|
touch_grabbed_token(token)
|
@@ -87,7 +76,7 @@ module SidekiqUniqueJobs
|
|
87
76
|
:unlock,
|
88
77
|
redis_pool,
|
89
78
|
keys: [exists_key, grabbed_key, available_key, version_key, UNIQUE_SET, unique_digest],
|
90
|
-
argv: [token,
|
79
|
+
argv: [token, ttl, lock_type],
|
91
80
|
)
|
92
81
|
end
|
93
82
|
|
@@ -97,12 +86,19 @@ module SidekiqUniqueJobs
|
|
97
86
|
# @return [true, false]
|
98
87
|
def locked?(token = nil)
|
99
88
|
token ||= jid
|
89
|
+
Scripts.call(
|
90
|
+
:convert_legacy_lock,
|
91
|
+
redis_pool,
|
92
|
+
keys: [grabbed_key, unique_digest],
|
93
|
+
argv: [token],
|
94
|
+
)
|
95
|
+
|
100
96
|
redis(redis_pool) { |conn| conn.hexists(grabbed_key, token) }
|
101
97
|
end
|
102
98
|
|
103
99
|
private
|
104
100
|
|
105
|
-
attr_reader :
|
101
|
+
attr_reader :unique_digest, :ttl, :jid, :redis_pool, :lock_type
|
106
102
|
|
107
103
|
def grab_token(timeout = nil)
|
108
104
|
redis(redis_pool) do |conn|
|
@@ -118,7 +114,10 @@ module SidekiqUniqueJobs
|
|
118
114
|
end
|
119
115
|
|
120
116
|
def touch_grabbed_token(token)
|
121
|
-
redis(redis_pool)
|
117
|
+
redis(redis_pool) do |conn|
|
118
|
+
conn.hset(grabbed_key, token, current_time.to_f)
|
119
|
+
conn.expire(grabbed_key, ttl) if ttl && lock_type == :until_expired
|
120
|
+
end
|
122
121
|
end
|
123
122
|
|
124
123
|
def return_token_or_block_value(token)
|
@@ -161,4 +160,5 @@ module SidekiqUniqueJobs
|
|
161
160
|
redis(&:time)
|
162
161
|
end
|
163
162
|
end
|
163
|
+
# rubocop:enable ClassLength
|
164
164
|
end
|
@@ -52,7 +52,11 @@ module SidekiqUniqueJobs
|
|
52
52
|
|
53
53
|
def logging_context(middleware_class, job_hash)
|
54
54
|
digest = job_hash["unique_digest"]
|
55
|
-
|
55
|
+
if defined?(Sidekiq::Logging)
|
56
|
+
"#{middleware_class} #{"DIG-#{digest}" if digest}"
|
57
|
+
else
|
58
|
+
{ middleware: middleware_class, unique_digest: digest }
|
59
|
+
end
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
@@ -23,7 +23,7 @@ module SidekiqUniqueJobs
|
|
23
23
|
return yield if unique_disabled?
|
24
24
|
|
25
25
|
SidekiqUniqueJobs::Job.add_uniqueness(item)
|
26
|
-
|
26
|
+
SidekiqUniqueJobs.with_context(logging_context(self.class, item)) do
|
27
27
|
lock.execute do
|
28
28
|
yield
|
29
29
|
end
|
@@ -33,6 +33,15 @@ module SidekiqUniqueJobs
|
|
33
33
|
config.logger
|
34
34
|
end
|
35
35
|
|
36
|
+
# :reek:ManualDispatch
|
37
|
+
def with_context(context, &block)
|
38
|
+
if logger.respond_to?(:with_context)
|
39
|
+
logger.with_context(context, &block)
|
40
|
+
elsif defined?(Sidekiq::Logging)
|
41
|
+
Sidekiq::Logging.with_context(context, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
36
45
|
# Set a new logger
|
37
46
|
# @param [Logger] other a new logger
|
38
47
|
def logger=(other)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
local grabbed_key = KEYS[1]
|
2
|
+
local unique_digest = KEYS[2]
|
3
|
+
|
4
|
+
local job_id = ARGV[1]
|
5
|
+
|
6
|
+
local function current_time()
|
7
|
+
local time = redis.call('time')
|
8
|
+
local s = time[1]
|
9
|
+
local ms = time[2]
|
10
|
+
local number = tonumber((s .. '.' .. ms))
|
11
|
+
|
12
|
+
return number
|
13
|
+
end
|
14
|
+
|
15
|
+
local old_token = redis.call('GET', unique_digest)
|
16
|
+
if old_token then
|
17
|
+
if old_token == job_id or old_token == '2' then
|
18
|
+
redis.call('DEL', unique_digest)
|
19
|
+
redis.call('HSET', grabbed_key, job_id, current_time())
|
20
|
+
end
|
21
|
+
end
|
data/redis/lock.lua
CHANGED
@@ -6,8 +6,9 @@ local available_key = KEYS[3]
|
|
6
6
|
local unique_keys = KEYS[4]
|
7
7
|
local unique_digest = KEYS[5]
|
8
8
|
|
9
|
-
local job_id
|
10
|
-
local
|
9
|
+
local job_id = ARGV[1]
|
10
|
+
local ttl = tonumber(ARGV[2])
|
11
|
+
local lock = ARGV[3]
|
11
12
|
|
12
13
|
local function current_time()
|
13
14
|
local time = redis.call('time')
|
@@ -18,11 +19,8 @@ local function current_time()
|
|
18
19
|
return number
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
local stored_token = redis.call('GET', exists_key)
|
22
|
+
local stored_token = redis.call('GET', exists_key)
|
24
23
|
if stored_token and stored_token ~= job_id then
|
25
|
-
-- redis.log(redis.LOG_DEBUG, "create.lua - jid: " .. job_id .. " - returning existing jid: " .. stored_token)
|
26
24
|
return stored_token
|
27
25
|
end
|
28
26
|
|
@@ -49,10 +47,15 @@ redis.call('DEL', grabbed_key)
|
|
49
47
|
redis.call('DEL', available_key)
|
50
48
|
redis.call('RPUSH', available_key, job_id)
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
-- The client should only set ttl for until_expired
|
51
|
+
-- The server should set ttl for all other jobs
|
52
|
+
if lock == "until_expired" and ttl then
|
53
|
+
-- We can't keep the key here because it will otherwise never be deleted
|
54
|
+
redis.call('SREM', unique_keys, unique_digest)
|
55
|
+
|
56
|
+
redis.call('EXPIRE', available_key, ttl)
|
57
|
+
redis.call('EXPIRE', exists_key, ttl)
|
58
|
+
redis.call('EXPIRE', unique_digest, ttl)
|
56
59
|
end
|
57
60
|
|
58
61
|
return job_id
|
data/redis/unlock.lua
CHANGED
@@ -5,19 +5,19 @@ local version_key = KEYS[4]
|
|
5
5
|
local unique_keys = KEYS[5]
|
6
6
|
local unique_digest = KEYS[6] -- TODO: Legacy support (Remove in v6.1)
|
7
7
|
|
8
|
-
local token
|
9
|
-
local
|
8
|
+
local token = ARGV[1]
|
9
|
+
local ttl = tonumber(ARGV[2])
|
10
|
+
local lock = ARGV[3]
|
10
11
|
|
11
|
-
redis.call('HDEL', grabbed_key, token)
|
12
12
|
redis.call('SREM', unique_keys, unique_digest)
|
13
13
|
|
14
|
-
if
|
15
|
-
redis.log(redis.LOG_DEBUG, "signal_locks.lua - expiring stale locks")
|
14
|
+
if ttl then
|
16
15
|
redis.call('SREM', unique_keys, unique_digest)
|
17
|
-
redis.call('EXPIRE', exists_key,
|
18
|
-
redis.call('EXPIRE',
|
19
|
-
redis.call('EXPIRE',
|
20
|
-
redis.call('EXPIRE',
|
16
|
+
redis.call('EXPIRE', exists_key, ttl)
|
17
|
+
redis.call('EXPIRE', grabbed_key, ttl)
|
18
|
+
redis.call('EXPIRE', available_key, ttl)
|
19
|
+
redis.call('EXPIRE', version_key, ttl) -- TODO: Legacy support (Remove in v6.1)
|
20
|
+
redis.call('EXPIRE', unique_digest, ttl) -- TODO: Legacy support (Remove in v6.1)
|
21
21
|
else
|
22
22
|
redis.call('DEL', exists_key)
|
23
23
|
redis.call('SREM', unique_keys, unique_digest)
|
@@ -28,6 +28,7 @@ else
|
|
28
28
|
redis.call('DEL', unique_digest) -- TODO: Legacy support (Remove in v6.1)
|
29
29
|
end
|
30
30
|
|
31
|
+
redis.call('HDEL', grabbed_key, token)
|
31
32
|
local count = redis.call('LPUSH', available_key, token)
|
32
33
|
redis.call('EXPIRE', available_key, 5)
|
33
34
|
return count
|
data/sidekiq-unique-jobs.gemspec
CHANGED
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
|
|
42
42
|
|
43
43
|
spec.require_paths = ["lib"]
|
44
44
|
spec.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.5"
|
45
|
-
spec.add_dependency "sidekiq", ">= 4.0", "<
|
45
|
+
spec.add_dependency "sidekiq", ">= 4.0", "< 7.0"
|
46
46
|
spec.add_dependency "thor", "~> 0"
|
47
47
|
|
48
48
|
spec.add_development_dependency "bundler", ">= 2.0"
|
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: 6.0.
|
4
|
+
version: 6.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikael Henriksson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '4.0'
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '7.0'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,7 +49,7 @@ dependencies:
|
|
49
49
|
version: '4.0'
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: '
|
52
|
+
version: '7.0'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: thor
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -340,6 +340,7 @@ files:
|
|
340
340
|
- lib/sidekiq_unique_jobs/web/views/unique_digests.erb
|
341
341
|
- lib/tasks/changelog.rake
|
342
342
|
- redis/acquire_lock.lua
|
343
|
+
- redis/convert_legacy_lock.lua
|
343
344
|
- redis/delete.lua
|
344
345
|
- redis/delete_by_digest.lua
|
345
346
|
- redis/delete_job_by_digest.lua
|