pmckee11-redis-lock 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83a23888f2a8facee8e44efa6bfed1787ccbaaff
4
- data.tar.gz: c90fec2dd78ab7d4deb6539cb3c526771371e5b4
3
+ metadata.gz: 290df5759f6a3511b52c04a4399e72c6f8fa63b3
4
+ data.tar.gz: 7d51790da0d3841fb80054146adae29e8c4a601c
5
5
  SHA512:
6
- metadata.gz: 9ad344a0f17edd109ac36d756ac6fdb0bb928442223828c88666757d8ecfe4a1c142cd59f5d006f9c2fb3c7ea87ca5adf89f68f28f7e181c8df3539d968fc274
7
- data.tar.gz: d147966d672dba6e0723759b89a40d87e16200d583a13bdb88efc7b62a2ccac049046745c805f34ce77f4011e747ee072c3bff4c5fa04dd5a7a399151541b7a2
6
+ metadata.gz: 16ea49364c09328c26190ec9b99dd7a0fe56342df44eec8d3e6c5dda99663577510f04ed12fbbe2199026d8b5d897a90562217bb16c46d90944a5a36ea8b57bb
7
+ data.tar.gz: 41f0d9710dcdb9acb844e8220bfae98a0751c46e6247f581e93e68bce5ea69e4c815658d45c6a05395af70103c9a28915fb75f3562439310e33e20619424187e
@@ -27,4 +27,4 @@ PLATFORMS
27
27
 
28
28
  DEPENDENCIES
29
29
  pmckee11-redis-lock!
30
- rspec
30
+ rspec (~> 3.0, >= 3.0)
data/README.md CHANGED
@@ -13,11 +13,37 @@ and then run bundler.
13
13
  Or run
14
14
 
15
15
  $ gem install pmckee11-redis-lock
16
-
16
+
17
17
  ## Background
18
18
 
19
19
  This implements a distributed lock with a timeout almost exactly as described in the redis documentation.
20
- There are a few other redis lock implementations in ruby, but none of them seemed to be using the newer features in redis that can yield a performance improvement (e.g. the expanded SET parameters and Lua scripting). Using this gem requires a redis 2.6.12 server, allowing it to leverage those newer features to make fewer round trips and provide better performance
20
+ There are a few other redis lock implementations in ruby, but none of them seemed to be using the newer features in redis that can yield a performance improvement (e.g. the expanded SET parameters and Lua scripting). Using this gem requires a redis 2.6.12 or newer server, allowing it to leverage those newer features to make fewer round trips and provide better performance
21
+
22
+ ## Usage
23
+
24
+ Create an instance of `Redis::Lock` with the desired redis connection and parameters. `auto_release_time` is the lock TTL in seconds (defaults to 10) and `base_sleep` is the amount of time in milliseconds to sleep after the first failure to acquire a lock (defaults to 100ms). Successive failures to acquire a lock result in exponential back off to prevent wasted cycles:
25
+
26
+ redis = Redis.new
27
+ my_lock = Redis::Lock.new(redis,
28
+ "my-lock-key",
29
+ :auto_release_time => LOCK_TTL_IN_SECS,
30
+ :base_sleep => SLEEP_IN_MS)
31
+
32
+ Once you have a lock, you can manually lock and unlock or pass a block to lock only around your code:
33
+
34
+ my_lock.lock
35
+ # Do stuff
36
+ my_lock.unlock
37
+
38
+ my_lock.do |lock|
39
+ # Do stuff
40
+ end
41
+
42
+ You can also configure the maximum amount of time in seconds to block on acquiring a lock (defaults to 10):
43
+
44
+ my_lock(5).do |lock|
45
+ # Do stuff
46
+ end
21
47
 
22
48
  ## Contributing
23
49
 
@@ -25,4 +51,4 @@ There are a few other redis lock implementations in ruby, but none of them seeme
25
51
  2. Create your feature branch (`git checkout -b my-new-feature`)
26
52
  3. Commit your changes (`git commit -am 'Added some feature'`)
27
53
  4. Push to the branch (`git push origin my-new-feature`)
28
- 5. Create new Pull Request
54
+ 5. Create new Pull Request
@@ -55,12 +55,17 @@ class Redis
55
55
  end
56
56
  end
57
57
 
58
+ # @return Boolean that is true if the lock is currently held by any process
59
+ def locked?
60
+ return !@redis.get(@key).nil?
61
+ end
62
+
58
63
  # Determines whether or not the lock is held by this instance. By default, this method relies on the expiration time
59
64
  # of the key as a performance optimization when possible. If this is undesirable for some reason, set force_remote
60
65
  # to true.
61
66
  # @param force_remote Boolean for whether to verify with a call to the redis server instead of using the lock time
62
67
  # @return Boolean that is true if this lock instance currently holds the lock
63
- def locked?(force_remote = false)
68
+ def locked_by_me?(force_remote = false)
64
69
  if @time_locked
65
70
  if force_remote
66
71
  return @redis.get(@key) == @instance_name
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  class Lock
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -19,5 +19,5 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
 
21
21
  gem.add_dependency "redis", '~> 3.0', '>= 3.0.5'
22
- gem.add_development_dependency "rspec"
22
+ gem.add_development_dependency "rspec", '~> 3.0', '>= 3.0'
23
23
  end
@@ -23,16 +23,18 @@ describe Redis::Lock do
23
23
  context "#lock" do
24
24
  it "should set an appropriate key in redis" do
25
25
  lock.lock
26
- @redis.get("lock:#{key}").should_not be_nil
26
+ expect(@redis.get("lock:#{key}")).not_to be_nil
27
27
  end
28
28
 
29
29
  context "when a block is provided" do
30
30
  it "locks before yielding and releases after" do
31
+ expect(lock).to receive(:test_message)
31
32
  lock.lock do |l|
32
- l.should == lock
33
- @redis.get("lock:#{key}").should_not be_nil
33
+ expect(l).to eq(lock)
34
+ l.test_message
35
+ expect(@redis.get("lock:#{key}")).not_to be_nil
34
36
  end
35
- @redis.get("lock:#{key}").should be_nil
37
+ expect(@redis.get("lock:#{key}")).to be_nil
36
38
  end
37
39
  end
38
40
 
@@ -45,8 +47,8 @@ describe Redis::Lock do
45
47
  other_lock.lock(2)
46
48
  fail()
47
49
  rescue => e
48
- (Time.now - time).should be_within(0.1).of(2.0)
49
- e.should be_a(Redis::Lock::AcquireLockTimeOut)
50
+ expect(Time.now - time).to be_within(0.1).of(2.0)
51
+ expect(e).to be_a(Redis::Lock::AcquireLockTimeOut)
50
52
  end
51
53
  end
52
54
  end
@@ -54,7 +56,7 @@ describe Redis::Lock do
54
56
  context "when initialized with auto_release_time" do
55
57
  it "sets the redis key with an appropriate expiration" do
56
58
  other_lock = Redis::Lock.new(@redis, key, :auto_release_time => 7)
57
- @redis.should_receive(:set).with("lock:#{key}", an_instance_of(String), :nx => true, :ex => 7).and_return(true)
59
+ expect(@redis).to receive(:set).with("lock:#{key}", an_instance_of(String), :nx => true, :ex => 7).and_return(true)
58
60
  other_lock.lock
59
61
  end
60
62
  end
@@ -62,12 +64,12 @@ describe Redis::Lock do
62
64
  context "when initialized with base_sleep" do
63
65
  it "retries with exponential back off starting at base_sleep millis" do
64
66
  other_lock = Redis::Lock.new(@redis, key, :base_sleep => 25)
65
- other_lock.should_receive(:sleep).with(0.025).ordered
66
- other_lock.should_receive(:sleep).with(0.05).ordered
67
- other_lock.should_receive(:sleep).with(0.1).ordered
68
- other_lock.should_receive(:sleep).with(0.2).ordered
69
- other_lock.should_receive(:sleep) do |sleep_time|
70
- sleep_time.should == 0.4
67
+ expect(other_lock).to receive(:sleep).with(0.025).ordered
68
+ expect(other_lock).to receive(:sleep).with(0.05).ordered
69
+ expect(other_lock).to receive(:sleep).with(0.1).ordered
70
+ expect(other_lock).to receive(:sleep).with(0.2).ordered
71
+ expect(other_lock).to receive(:sleep) do |sleep_time|
72
+ expect(sleep_time).to eq(0.4)
71
73
  lock.unlock
72
74
  end.ordered
73
75
  lock.lock
@@ -80,7 +82,7 @@ describe Redis::Lock do
80
82
  it "should delete an appropriate key from redis" do
81
83
  lock.lock
82
84
  lock.unlock
83
- @redis.get("lock:#{key}").should be_nil
85
+ expect(@redis.get("lock:#{key}")).to be_nil
84
86
  end
85
87
 
86
88
  it "should not delete a lock held by another instance" do
@@ -88,13 +90,13 @@ describe Redis::Lock do
88
90
  other_lock.lock
89
91
  sleep(1.1)
90
92
  lock.lock
91
- other_lock.unlock
92
- @redis.get("lock:#{key}").should_not be_nil
93
+ other_lock.unlock(true)
94
+ expect(@redis.get("lock:#{key}")).not_to be_nil
93
95
  end
94
96
 
95
97
  context "when the instance has not been locked" do
96
98
  it "is a no op" do
97
- @redis.should_not_receive(:eval)
99
+ expect(@redis).not_to receive(:eval)
98
100
  lock.unlock
99
101
  end
100
102
  end
@@ -104,7 +106,7 @@ describe Redis::Lock do
104
106
  other_lock = Redis::Lock.new(@redis, key, :auto_release_time => 1)
105
107
  other_lock.lock
106
108
  sleep(1)
107
- @redis.should_not_receive(:eval)
109
+ expect(@redis).not_to receive(:eval)
108
110
  other_lock.unlock
109
111
  end
110
112
 
@@ -113,7 +115,7 @@ describe Redis::Lock do
113
115
  other_lock = Redis::Lock.new(@redis, key, :auto_release_time => 1)
114
116
  other_lock.lock
115
117
  sleep(1)
116
- @redis.should_receive(:eval).with(Redis::Lock::UNLOCK_LUA_SCRIPT, ["lock:#{key}"], instance_of(Array)).once
118
+ expect(@redis).to receive(:eval).with(Redis::Lock::UNLOCK_LUA_SCRIPT, ["lock:#{key}"], instance_of(Array)).once
117
119
  other_lock.unlock(true)
118
120
  end
119
121
  end
@@ -121,18 +123,40 @@ describe Redis::Lock do
121
123
  end
122
124
 
123
125
  context "#locked?" do
126
+ context "when the lock is held" do
127
+ before :each do
128
+ lock.lock
129
+ end
130
+
131
+ after :each do
132
+ lock.unlock
133
+ end
134
+
135
+ it "returns true" do
136
+ expect(lock.locked?).to be_truthy
137
+ end
138
+ end
139
+
140
+ context "when the lock is not held" do
141
+ it "returns false" do
142
+ expect(lock.locked?).to be_falsey
143
+ end
144
+ end
145
+ end
146
+
147
+ context "#locked_by_me?" do
124
148
  it "correctly determines if the instance holds the lock" do
125
- lock.locked?.should be_false
149
+ expect(lock.locked_by_me?).to be_falsey
126
150
  lock.lock
127
- lock.locked?.should be_true
151
+ expect(lock.locked_by_me?).to be_truthy
128
152
  lock.unlock
129
- lock.locked?.should be_false
153
+ expect(lock.locked_by_me?).to be_falsey
130
154
  end
131
155
 
132
156
  context "when the instance has not been locked" do
133
157
  it "is a no op" do
134
- @redis.should_not_receive(:eval)
135
- lock.unlock
158
+ expect(@redis).not_to receive(:get)
159
+ lock.locked_by_me?
136
160
  end
137
161
  end
138
162
 
@@ -141,8 +165,8 @@ describe Redis::Lock do
141
165
  other_lock = Redis::Lock.new(@redis, key, :auto_release_time => 1)
142
166
  other_lock.lock
143
167
  sleep(1)
144
- @redis.should_not_receive(:get)
145
- other_lock.locked?.should be_false
168
+ expect(@redis).not_to receive(:get)
169
+ expect(other_lock.locked_by_me?).to be_falsey
146
170
  end
147
171
 
148
172
  context "but force_remote is true" do
@@ -150,11 +174,11 @@ describe Redis::Lock do
150
174
  other_lock = Redis::Lock.new(@redis, key, :auto_release_time => 1)
151
175
  other_lock.lock
152
176
  sleep(1)
153
- @redis.should_receive(:get).once.and_return(nil)
154
- other_lock.locked?(true).should be_false
177
+ expect(@redis).to receive(:get).once.and_return(nil)
178
+ expect(other_lock.locked_by_me?(true)).to be_falsey
155
179
  end
156
180
  end
157
181
  end
158
182
  end
159
183
 
160
- end
184
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pmckee11-redis-lock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter McKee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-26 00:00:00.000000000 Z
11
+ date: 2015-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -34,16 +34,22 @@ dependencies:
34
34
  name: rspec
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
37
40
  - - ">="
38
41
  - !ruby/object:Gem::Version
39
- version: '0'
42
+ version: '3.0'
40
43
  type: :development
41
44
  prerelease: false
42
45
  version_requirements: !ruby/object:Gem::Requirement
43
46
  requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
44
50
  - - ">="
45
51
  - !ruby/object:Gem::Version
46
- version: '0'
52
+ version: '3.0'
47
53
  description: Distributed lock using ruby redis
48
54
  email:
49
55
  - pmckee11@gmail.com
@@ -82,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
88
  version: '0'
83
89
  requirements: []
84
90
  rubyforge_project:
85
- rubygems_version: 2.2.2
91
+ rubygems_version: 2.4.5
86
92
  signing_key:
87
93
  specification_version: 4
88
94
  summary: Distributed lock using ruby redis