mlanett-redis-lock 0.2.4 → 0.2.7
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 +7 -0
- data/Gemfile +1 -1
- data/README.md +18 -15
- data/lib/redis-lock/version.rb +1 -1
- data/lib/redis-lock.rb +20 -11
- data/redis-lock.gemspec +1 -1
- data/spec/redis_lock_spec.rb +13 -0
- metadata +13 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 148ebe29b3ebd72bd6cc37ab0e34b471326c8076
|
4
|
+
data.tar.gz: 2e6110d8ba371f5ad6d7ee40ae5e35ad1b555c78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 52b8e7beac0570d9bd348cf0ec8f90a5f1dc3ff5fa8ebde0e5e44a7d04f4dde99614e1e799d695bc5184a314a3bf39c096b3cd6c09bf7c56b9f784e30b712a79
|
7
|
+
data.tar.gz: 9fa50ba005240a11dee08225481842012c52a1d2b25f0bcfbd0f872509f46d55a72b4e36646e62214163891ec86caa16a309cd3d150b3fd600ff44292022c4f8
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -33,27 +33,30 @@ rather than acquiring the lock with a very long lifetime which will result in lo
|
|
33
33
|
|
34
34
|
A lock needs an owner. Redis::Lock defaults to using an owner id of HOSTNAME:PID.
|
35
35
|
|
36
|
-
A lock may need more than one attempt to acquire it. Redis::Lock offers
|
37
|
-
|
36
|
+
A lock may need more than one attempt to acquire it. Redis::Lock offers an acquisition timeout; this defaults to 10 seconds.
|
37
|
+
|
38
|
+
There are two lock methods: Redis#lock, which is more convenient, and Redis::Lock#lock.
|
39
|
+
Notice there are two timeouts: the lock's lifetime (```:life``` option) and the acquisition timeout, which is less important.
|
40
|
+
The acquisition timeout is set via the :acquire option to Redis#lock or passed directly to Redis::Lock#lock.
|
38
41
|
|
39
42
|
## Usage
|
40
43
|
|
41
|
-
This gem adds lock() and unlock() to Redis instances.
|
42
|
-
lock() takes a block and is safer than using lock() and unlock() separately.
|
43
|
-
lock() takes a key and lifetime and optionally
|
44
|
+
This gem adds `lock()` and `unlock()` to Redis instances.
|
45
|
+
`lock()` takes a block and is safer than using `lock()` and `unlock()` separately.
|
46
|
+
`lock()` takes a key and lifetime and optionally an acquisition timeout (defaulting to 10 seconds).
|
44
47
|
|
45
|
-
redis.lock("test") { |lock| do_something }
|
48
|
+
redis.lock("test") { |lock| do_something }
|
46
49
|
|
47
|
-
redis.lock("test") do |lock|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
50
|
+
redis.lock("test", life: 2*60, acquire: 2) do |lock|
|
51
|
+
array.each do |entry|
|
52
|
+
do_something(entry)
|
53
|
+
lock.extend_life(60)
|
54
|
+
end
|
55
|
+
end
|
53
56
|
|
54
|
-
##
|
57
|
+
## Goals
|
55
58
|
|
56
|
-
|
59
|
+
I wrote this when noticing that other lock gems were using non-robust approaches.
|
57
60
|
|
58
61
|
You need to be able to handle race conditions while acquiring the lock.
|
59
62
|
You need to be able to handle the owner of the lock failing to release it.
|
@@ -64,7 +67,7 @@ The code which cleans the stale lock must not interfere with a different owner a
|
|
64
67
|
|
65
68
|
## Contributors
|
66
69
|
|
67
|
-
Alexander Lang (langalex), Jonathan Hyman (jonhyman), Jamie Cobbett (jamiecobbett),
|
70
|
+
Alexander Lang (langalex), Jonathan Hyman (jonhyman), Jamie Cobbett (jamiecobbett), Ravil Bayramgalin (brainopia), and Tom Mornini (tmornini) have contributed to Redis Lock.
|
68
71
|
|
69
72
|
## Contributing
|
70
73
|
|
data/lib/redis-lock/version.rb
CHANGED
data/lib/redis-lock.rb
CHANGED
@@ -21,9 +21,9 @@ class Redis
|
|
21
21
|
|
22
22
|
# @param redis is a Redis instance
|
23
23
|
# @param key is a unique string identifying the object to lock, e.g. "user-1"
|
24
|
-
# @param options[:life]
|
24
|
+
# @param options[:life] should be set, but defaults to 1 minute
|
25
25
|
# @param options[:owner] may be set, but defaults to HOSTNAME:PID
|
26
|
-
# @param options[:sleep]
|
26
|
+
# @param options[:sleep] is used when trying to acquire the lock; milliseconds; defaults to 125.
|
27
27
|
def initialize( redis, key, options = {} )
|
28
28
|
check_keys( options, :owner, :life, :sleep )
|
29
29
|
@redis = redis
|
@@ -35,8 +35,9 @@ class Redis
|
|
35
35
|
@sleep_in_ms = options[:sleep] || 125
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
# @param acquisition_timeout defaults to 10 seconds and can be used to determine how long to wait for a lock.
|
39
|
+
def lock( acquisition_timeout = 10, &block )
|
40
|
+
do_lock_with_timeout(acquisition_timeout) or raise LockNotAcquired.new(key)
|
40
41
|
if block then
|
41
42
|
begin
|
42
43
|
result = (block.arity == 1) ? block.call(self) : block.call
|
@@ -74,9 +75,9 @@ class Redis
|
|
74
75
|
# internal api
|
75
76
|
#
|
76
77
|
|
77
|
-
def do_lock_with_timeout(
|
78
|
+
def do_lock_with_timeout( acquisition_timeout )
|
78
79
|
locked = false
|
79
|
-
with_timeout(
|
80
|
+
with_timeout(acquisition_timeout) { locked = do_lock }
|
80
81
|
locked
|
81
82
|
end
|
82
83
|
|
@@ -166,9 +167,10 @@ class Redis
|
|
166
167
|
return false
|
167
168
|
end
|
168
169
|
|
169
|
-
# Calls block until it returns true or times out.
|
170
|
+
# Calls block until it returns true or times out.
|
170
171
|
# @param block should return true if successful, false otherwise
|
171
172
|
# @returns true if successful, false otherwise
|
173
|
+
# Note: at one time I thought of using a backoff strategy, but don't think that's important now.
|
172
174
|
def with_timeout( timeout, &block )
|
173
175
|
expire = Time.now + timeout.to_f
|
174
176
|
sleepy = @sleep_in_ms / 1000.to_f()
|
@@ -178,7 +180,6 @@ class Redis
|
|
178
180
|
log :debug, "Timeout for #{@key}" and return false if Time.now + sleepy > expire
|
179
181
|
sleep(sleepy)
|
180
182
|
# might like a different strategy, but general goal is not use 100% cpu while contending for a lock.
|
181
|
-
# sleepy = [ sleepy * 2, ( expire - Time.now ) / 4 ].min
|
182
183
|
end
|
183
184
|
end
|
184
185
|
|
@@ -219,14 +220,22 @@ class Redis
|
|
219
220
|
|
220
221
|
# Convenience methods
|
221
222
|
|
222
|
-
# @
|
223
|
+
# @param key is a unique string identifying the object to lock, e.g. "user-1"
|
224
|
+
# @options are as specified for Redis::Lock#lock (including :life)
|
225
|
+
# @param options[:life] should be set, but defaults to 1 minute
|
226
|
+
# @param options[:owner] may be set, but defaults to HOSTNAME:PID
|
227
|
+
# @param options[:sleep] is used when trying to acquire the lock; milliseconds; defaults to 125.
|
228
|
+
# @param options[:acquire] defaults to 10 seconds and can be used to determine how long to wait for a lock.
|
223
229
|
def lock( key, options = {}, &block )
|
224
230
|
acquire = options.delete(:acquire) || 10
|
225
|
-
|
231
|
+
|
232
|
+
lock = Redis::Lock.new self, key, options
|
233
|
+
|
234
|
+
block_given? ? lock.lock(acquire, &block) : lock
|
226
235
|
end
|
227
236
|
|
228
237
|
def unlock( key )
|
229
|
-
Lock( self, key ).unlock
|
238
|
+
Redis::Lock.new( self, key ).unlock
|
230
239
|
end
|
231
240
|
|
232
241
|
end # Redis
|
data/redis-lock.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require File.expand_path('../lib/redis-lock/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = ["Mark Lanett", "Ravil Bayramgalin", "Jamie Cobbett", "Jonathan Hyman", "Alexander Lang"]
|
5
|
+
gem.authors = ["Mark Lanett", "Ravil Bayramgalin", "Jamie Cobbett", "Jonathan Hyman", "Alexander Lang", "Tom Mornini"]
|
6
6
|
gem.email = ["mark.lanett@gmail.com"]
|
7
7
|
gem.description = %q{Pessimistic locking using Redis}
|
8
8
|
gem.summary = %q{Pessimistic locking using Redis}
|
data/spec/redis_lock_spec.rb
CHANGED
@@ -136,4 +136,17 @@ describe Redis::Lock, redis: true do
|
|
136
136
|
# We leave [ present, present ] to be unspecified.
|
137
137
|
end
|
138
138
|
|
139
|
+
example "How to get a lock using the helper when passing a block" do
|
140
|
+
redis.lock "mykey", life: 10, acquire: 1 do |lock|
|
141
|
+
lock.extend_life 10
|
142
|
+
:return_value_of_block
|
143
|
+
end.should eql(:return_value_of_block)
|
144
|
+
end
|
145
|
+
|
146
|
+
example "How to get a lock using the helper when not passing a block" do
|
147
|
+
lock = redis.lock "mykey", life: 10, acquire: 1
|
148
|
+
lock.should be_an_instance_of(Redis::Lock)
|
149
|
+
lock.unlock
|
150
|
+
end
|
151
|
+
|
139
152
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mlanett-redis-lock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.7
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mark Lanett
|
@@ -10,25 +9,24 @@ authors:
|
|
10
9
|
- Jamie Cobbett
|
11
10
|
- Jonathan Hyman
|
12
11
|
- Alexander Lang
|
12
|
+
- Tom Mornini
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2015-10-22 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: redis
|
20
20
|
requirement: !ruby/object:Gem::Requirement
|
21
|
-
none: false
|
22
21
|
requirements:
|
23
|
-
- -
|
22
|
+
- - ">="
|
24
23
|
- !ruby/object:Gem::Version
|
25
24
|
version: '0'
|
26
25
|
type: :runtime
|
27
26
|
prerelease: false
|
28
27
|
version_requirements: !ruby/object:Gem::Requirement
|
29
|
-
none: false
|
30
28
|
requirements:
|
31
|
-
- -
|
29
|
+
- - ">="
|
32
30
|
- !ruby/object:Gem::Version
|
33
31
|
version: '0'
|
34
32
|
description: Pessimistic locking using Redis
|
@@ -38,9 +36,9 @@ executables: []
|
|
38
36
|
extensions: []
|
39
37
|
extra_rdoc_files: []
|
40
38
|
files:
|
41
|
-
- .gitignore
|
42
|
-
- .rspec
|
43
|
-
- .travis.yml
|
39
|
+
- ".gitignore"
|
40
|
+
- ".rspec"
|
41
|
+
- ".travis.yml"
|
44
42
|
- Gemfile
|
45
43
|
- Gemfile-redis2
|
46
44
|
- Gemfile-redis2.lock
|
@@ -60,27 +58,26 @@ files:
|
|
60
58
|
- test/stress.rb
|
61
59
|
homepage: ''
|
62
60
|
licenses: []
|
61
|
+
metadata: {}
|
63
62
|
post_install_message:
|
64
63
|
rdoc_options: []
|
65
64
|
require_paths:
|
66
65
|
- lib
|
67
66
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
67
|
requirements:
|
70
|
-
- -
|
68
|
+
- - ">="
|
71
69
|
- !ruby/object:Gem::Version
|
72
70
|
version: '0'
|
73
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
72
|
requirements:
|
76
|
-
- -
|
73
|
+
- - ">="
|
77
74
|
- !ruby/object:Gem::Version
|
78
75
|
version: '0'
|
79
76
|
requirements: []
|
80
77
|
rubyforge_project:
|
81
|
-
rubygems_version:
|
78
|
+
rubygems_version: 2.4.5.1
|
82
79
|
signing_key:
|
83
|
-
specification_version:
|
80
|
+
specification_version: 4
|
84
81
|
summary: Pessimistic locking using Redis
|
85
82
|
test_files:
|
86
83
|
- spec/helper.rb
|