pmckee11-redis-lock 0.1.0 → 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 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