redis_exp_lock 0.1 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/redis_exp_lock/version.rb +2 -2
- data/lib/redis_exp_lock.rb +86 -86
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 058391736f5480d69820f433bc306b6b358ac239
|
4
|
+
data.tar.gz: 94061a289cc41fff4f1c348df17c6b45529af01c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3868e179ca52f9ac3d9dee70d65beff38031aff0248948d2ac7bfe0803ee5ffb1dd3f28bc99aee863cd8bc280197c3429907963c0a585c863c1b933df33c98d
|
7
|
+
data.tar.gz: 60f13403deec8c2b47ebe77325d13935c491cb27ef3334099b8eb72c72dd961e45f2e66a908eaa3353b1b34af79b20cf44dc8be490d2a5fa5e7414e5968345c1
|
data/README.md
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
class RedisExpLock
|
2
|
-
|
3
|
-
end
|
2
|
+
VERSION = '0.1.1'
|
3
|
+
end
|
data/lib/redis_exp_lock.rb
CHANGED
@@ -2,96 +2,96 @@ require 'shavaluator'
|
|
2
2
|
|
3
3
|
class RedisExpLock
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
5
|
+
# Errors
|
6
|
+
class TooManyLockAttemptsError < RuntimeError; end
|
7
|
+
class AlreadyAcquiredLockError < RuntimeError; end
|
8
|
+
|
9
|
+
LUA = {
|
10
|
+
# Deletes keys if they equal the given values
|
11
|
+
:delequal => """
|
12
|
+
local deleted = 0
|
13
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
14
|
+
return redis.call('DEL', KEYS[1])
|
15
|
+
end
|
16
|
+
return 0
|
17
|
+
""",
|
18
|
+
}
|
19
|
+
|
20
|
+
attr_reader :redis, :lock_key, :lock_uuid, :expiry, :retries, :retry_interval
|
21
|
+
|
22
|
+
def initialize(lock_key, opts)
|
23
|
+
defaults = {
|
24
|
+
:expiry => nil, # in seconds
|
25
|
+
:retries => 0,
|
26
|
+
:retry_interval => 0.01, # in seconds
|
27
|
+
}
|
28
|
+
opts = {}.merge(defaults).merge(opts)
|
29
|
+
|
30
|
+
@lock_key = lock_key.to_s
|
31
|
+
raise ArgumentError.new('Invalid lock key') unless @lock_key.size > 0
|
32
|
+
@lock_uuid = nil
|
33
|
+
|
34
|
+
@redis = opts[:redis]
|
35
|
+
@shavaluator = Shavaluator.new(:redis => @redis)
|
36
|
+
@shavaluator.add(LUA)
|
37
|
+
|
38
|
+
@expiry = opts[:expiry]
|
39
|
+
@retries = opts[:retries]
|
40
|
+
@retry_interval = opts[:retry_interval]
|
41
|
+
end
|
42
|
+
|
43
|
+
def locked?
|
44
|
+
!@lock_uuid.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def key_locked?
|
48
|
+
@redis.exists(@lock_key)
|
49
|
+
end
|
50
|
+
|
51
|
+
def key_owned?
|
52
|
+
!@lock_uuid.nil? && @lock_uuid == @redis.get(@lock_key)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Attempt to acquire the lock, returning true if the lock was succesfully
|
56
|
+
# acquired, and false if not.
|
57
|
+
def try_lock
|
58
|
+
raise AlreadyAcquiredLockError if locked?
|
59
|
+
|
60
|
+
uuid = SecureRandom.uuid
|
61
|
+
set_opts = {
|
62
|
+
:nx => true
|
63
|
+
}
|
64
64
|
set_opts[:px] = Integer(@expiry * 1000) if @expiry
|
65
65
|
|
66
66
|
if @redis.set(@lock_key, uuid, set_opts)
|
67
|
-
|
68
|
-
|
67
|
+
@lock_uuid = uuid
|
68
|
+
true
|
69
69
|
else
|
70
|
-
|
70
|
+
false
|
71
71
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
72
|
+
end
|
73
|
+
|
74
|
+
def lock
|
75
|
+
attempts = 0
|
76
|
+
while attempts <= @retries
|
77
|
+
attempts += 1
|
78
|
+
return attempts if try_lock
|
79
|
+
sleep @retry_interval
|
80
|
+
end
|
81
|
+
raise TooManyLockAttemptsError
|
82
|
+
end
|
83
|
+
|
84
|
+
def unlock
|
85
|
+
return false unless locked?
|
86
|
+
was_locked = @shavaluator.exec(:delequal, :keys => [@lock_key], :argv => [@lock_uuid]) == 1
|
87
|
+
@lock_uuid = nil
|
88
|
+
was_locked
|
89
|
+
end
|
90
|
+
|
91
|
+
def synchronize(&crit_sec)
|
92
|
+
attempts = lock
|
93
|
+
crit_sec.call attempts
|
94
|
+
unlock
|
95
|
+
end
|
96
96
|
|
97
97
|
end
|