mlanett-redis-lock 0.2.4 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -4,10 +4,10 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development do
7
+ gem "guard"
7
8
  gem "guard-rspec"
8
9
  gem "rb-fsevent" # for guard
9
10
  gem "rspec"
10
- gem "ruby-debug19", require: false
11
11
  end
12
12
 
13
13
  group :test do
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 a timeout; this defaults to 10 seconds.
37
- It uses exponential backoff with sleeps so it's fairly safe to use longer timeouts.
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 a timeout (otherwise defaulting to 10 second).
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
- array.each do |entry|
49
- do_something(entry)
50
- lock.extend_life(60)
51
- end
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
- ## Problems
57
+ ## Goals
55
58
 
56
- Why do other gems get this wrong?
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), and Ravil Bayramgalin (brainopia) have contributed to Redis Lock.
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
 
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  class Lock
3
- VERSION = "0.2.4"
3
+ VERSION = "0.2.7"
4
4
  end
5
5
  end
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] may be set, but defaults to 1 minute
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] optional, number of milliseconds to sleep when lock is held, defaults to 125
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
- def lock( timeout = 10, &block )
39
- do_lock_with_timeout(timeout) or raise LockNotAcquired.new(key)
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( timeout )
78
+ def do_lock_with_timeout( acquisition_timeout )
78
79
  locked = false
79
- with_timeout(timeout) { locked = do_lock }
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. TODO: Use exponential backoff.
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
- # @option timeout defaults to 10 seconds
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
- Lock.new( self, key, options ).lock( acquire, &block )
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}
@@ -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.4
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: 2013-07-01 00:00:00.000000000 Z
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: 1.8.23
78
+ rubygems_version: 2.4.5.1
82
79
  signing_key:
83
- specification_version: 3
80
+ specification_version: 4
84
81
  summary: Pessimistic locking using Redis
85
82
  test_files:
86
83
  - spec/helper.rb