redlock 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 86073e680a1deb905852ddfcd28042cf81729875
4
- data.tar.gz: 76cffc3d01b4fa649ad4ae4276149453282c0ed4
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzQwMDRhZWQ2ZjUyM2FjMTgxMzJiY2Q1ZmY5YzI3ODk1ZWY4NTNmMA==
5
+ data.tar.gz: !binary |-
6
+ ZDliZjZlMmM3OGNmZGMyYzhlNWI3YjBlMmUyNGRmNGY0Yjk0N2FkYw==
5
7
  SHA512:
6
- metadata.gz: 8b0687bd912eff82bb3f4607de313d681d1e18971cbd3b6b484bae0fabae38b258ef423f0c00256b45e633fbc83abea9b38c57fbf08ce4d6567a2c254701eeb7
7
- data.tar.gz: 86dc485ebc704b9d46bd6878d18f9b7403c13840721a2475b4b61b5c7b4099a40db3375045df8c8be7e9270d52f9560854b489a3656805046d995e253b1d126b
8
+ metadata.gz: !binary |-
9
+ ZTZjYWUyNmI2NTliZjliODZkM2ZhYzczZDAyM2RlM2FiY2Y5MTkxMDk4YjVk
10
+ YzVhMGJjMjBiMTM4NDYzY2ZkNWNiYzRmODk5YWFlZTJlMzczMTZlMzI4ZmRh
11
+ YTNkZDNhNjgxNzcxOTlhNGE2YTdjNzgyZTgwNTY0YWY4OTUwMjc=
12
+ data.tar.gz: !binary |-
13
+ NDllNDgxMmQ0ODk1NTdlNTNkMjczN2EyYjQyMjE2MWU5YmJmMDVlMmJkY2Q1
14
+ YTZjNTE5NjFjNTI3Mjc3NzJiZDBlMDIwYzUwM2NlMGM1YjE0NDVkNDIzODFm
15
+ MjVhNjU3OTI4NzY0YzY3OTE1ZDhiNGRhNmRlMzM5OGE3YjczMTI=
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  *.gem
2
2
  coverage/
3
+ .bundle/
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- redlock (0.1.7)
5
- redis (~> 3, >= 3.3.0)
4
+ redlock (0.1.8)
5
+ redis (~> 3, >= 3.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -45,11 +45,7 @@ PLATFORMS
45
45
  ruby
46
46
 
47
47
  DEPENDENCIES
48
- bundler (~> 1.12, >= 1.12.3)
49
48
  coveralls (~> 0.8.13)
50
49
  rake (~> 11.1, >= 11.1.2)
51
50
  redlock!
52
- rspec (~> 3.4, >= 3.4.0)
53
-
54
- BUNDLED WITH
55
- 1.12.3
51
+ rspec (~> 3, >= 3.0.0)
data/README.md CHANGED
@@ -95,21 +95,34 @@ rescue Redlock::LockError
95
95
  end
96
96
  ```
97
97
 
98
- To extend the life of the lock, provided that you didn't let it expire:
98
+ To extend the life of the lock:
99
99
 
100
100
  ```ruby
101
101
  begin
102
102
  block_result = lock_manager.lock!("resource_key", 2000) do |lock_info|
103
103
  # critical code
104
- lock_manager.extend_life!(lock_info, 3000)
104
+ lock_manager.lock("resource key", 3000, extend: lock_info)
105
105
  # more critical code
106
106
  end
107
107
  rescue Redlock::LockError
108
108
  # error handling
109
109
  end
110
110
  ```
111
- There's also a non-bang version that returns true when the lock was
112
- extended
111
+
112
+ The above code will also acquire the lock if the previous lock has expired and the lock is currently free. Keep in mind that this means the lock could have been acquired by someone else in the meantime. To only extend the life of the lock if currently locked by yourself, use `extend_life` parameter:
113
+
114
+ ```ruby
115
+ begin
116
+ block_result = lock_manager.lock!("resource_key", 2000) do |lock_info|
117
+ # critical code
118
+ lock_manager.lock("resource key", 3000, extend: lock_info, extend_life: true)
119
+ # more critical code, only if lock was still hold
120
+ end
121
+ rescue Redlock::LockError
122
+ # error handling
123
+ end
124
+ ```
125
+
113
126
 
114
127
  ## Run tests
115
128
 
@@ -37,8 +37,8 @@ module Redlock
37
37
  # +extend+: A lock ("lock_info") to extend.
38
38
  # +block+:: an optional block to be executed; after its execution, the lock (if successfully
39
39
  # acquired) is automatically unlocked.
40
- def lock(resource, ttl, extend: nil, &block)
41
- lock_info = try_lock_instances(resource, ttl, extend)
40
+ def lock(resource, ttl, options = {}, &block)
41
+ lock_info = try_lock_instances(resource, ttl, options)
42
42
 
43
43
  if block_given?
44
44
  begin
@@ -52,30 +52,6 @@ module Redlock
52
52
  end
53
53
  end
54
54
 
55
- def extend_life(to_extend, ttl)
56
- value = to_extend.fetch(:value)
57
- resource = to_extend.fetch(:resource)
58
-
59
-
60
- extended, time_elapsed = timed do
61
- @servers.all? { |s| s.extend_life(resource, value, ttl) }
62
- end
63
-
64
- validity = ttl - time_elapsed - drift(ttl)
65
-
66
- if extended
67
- { validity: validity, resource: resource, value: value }
68
- else
69
- @servers.each { |s| s.unlock(resource, value) }
70
- false
71
- end
72
- end
73
-
74
- def extend_life!(to_extend, ttl)
75
- new_lock_info = self.extend_life(to_extend, ttl)
76
- raise LockError, 'failed to extend lock' unless new_lock_info
77
- end
78
-
79
55
  # Unlocks a resource.
80
56
  # Params:
81
57
  # +lock_info+:: the lock that has been acquired when you locked the resource.
@@ -86,10 +62,10 @@ module Redlock
86
62
  # Locks a resource, executing the received block only after successfully acquiring the lock,
87
63
  # and returning its return value as a result.
88
64
  # See Redlock::Client#lock for parameters.
89
- def lock!(*args, **keyword_args)
65
+ def lock!(*args)
90
66
  fail 'No block passed' unless block_given?
91
67
 
92
- lock(*args, **keyword_args) do |lock_info|
68
+ lock(*args) do |lock_info|
93
69
  raise LockError, 'failed to acquire lock' unless lock_info
94
70
  return yield
95
71
  end
@@ -115,7 +91,7 @@ module Redlock
115
91
  end
116
92
  eos
117
93
 
118
- EXTEND_LOCK_SCRIPT = <<-eos
94
+ EXTEND_LIFE_SCRIPT = <<-eos
119
95
  if redis.call("get", KEYS[1]) == ARGV[1] then
120
96
  redis.call("expire", KEYS[1], ARGV[2])
121
97
  return 0
@@ -124,7 +100,6 @@ module Redlock
124
100
  end
125
101
  eos
126
102
 
127
-
128
103
  def initialize(connection)
129
104
  if connection.respond_to?(:client)
130
105
  @redis = connection
@@ -141,9 +116,9 @@ module Redlock
141
116
  end
142
117
  end
143
118
 
144
- def extend_life(resource, val, ttl)
119
+ def extend(resource, val, ttl)
145
120
  recover_from_script_flush do
146
- rc = @redis.evalsha @extend_lock_script_sha, keys: [resource], argv: [val, ttl]
121
+ rc = @redis.evalsha @extend_life_script_sha, keys: [resource], argv: [val, ttl]
147
122
  rc == 0
148
123
  end
149
124
  end
@@ -161,7 +136,7 @@ module Redlock
161
136
  def load_scripts
162
137
  @unlock_script_sha = @redis.script(:load, UNLOCK_SCRIPT)
163
138
  @lock_script_sha = @redis.script(:load, LOCK_SCRIPT)
164
- @extend_lock_script_sha = @redis.script(:load, EXTEND_LOCK_SCRIPT)
139
+ @extend_life_script_sha = @redis.script(:load, EXTEND_LIFE_SCRIPT)
165
140
  end
166
141
 
167
142
  def recover_from_script_flush
@@ -183,9 +158,11 @@ module Redlock
183
158
  end
184
159
  end
185
160
 
186
- def try_lock_instances(resource, ttl, extend)
187
- @retry_count.times do
188
- lock_info = lock_instances(resource, ttl, extend)
161
+ def try_lock_instances(resource, ttl, options)
162
+ tries = options[:extend] ? 1 : @retry_count
163
+
164
+ tries.times do
165
+ lock_info = lock_instances(resource, ttl, options)
189
166
  return lock_info if lock_info
190
167
 
191
168
  # Wait a random delay before retrying
@@ -195,11 +172,12 @@ module Redlock
195
172
  false
196
173
  end
197
174
 
198
- def lock_instances(resource, ttl, extend)
199
- value = extend ? extend.fetch(:value) : SecureRandom.uuid
175
+ def lock_instances(resource, ttl, options)
176
+ value = options[:extend] ? options[:extend].fetch(:value) : SecureRandom.uuid
177
+ method = options[:extend_life] ? :extend : :lock
200
178
 
201
179
  locked, time_elapsed = timed do
202
- @servers.select { |s| s.lock(resource, value, ttl) }.size
180
+ @servers.select { |s| s.send(method, resource, value, ttl) }.size
203
181
  end
204
182
 
205
183
  validity = ttl - time_elapsed - drift(ttl)
@@ -4,17 +4,17 @@ module Redlock
4
4
 
5
5
  alias_method :try_lock_instances_without_testing, :try_lock_instances
6
6
 
7
- def try_lock_instances(resource, ttl, extend)
7
+ def try_lock_instances(resource, ttl, options)
8
8
  if @testing_mode == :bypass
9
9
  {
10
10
  validity: ttl,
11
11
  resource: resource,
12
- value: extend ? extend.fetch(:value) : SecureRandom.uuid
12
+ value: options[:extend] ? options[:extend].fetch(:value) : SecureRandom.uuid
13
13
  }
14
14
  elsif @testing_mode == :fail
15
15
  false
16
16
  else
17
- try_lock_instances_without_testing resource, ttl, extend
17
+ try_lock_instances_without_testing resource, ttl, options
18
18
  end
19
19
  end
20
20
 
@@ -1,3 +1,3 @@
1
1
  module Redlock
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.8'
3
3
  end
@@ -18,10 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'redis', '~> 3', '>= 3.3.0'
21
+ spec.add_dependency 'redis', '~> 3', '>= 3.0.0'
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.12', '>= 1.12.3'
24
23
  spec.add_development_dependency "coveralls", "~> 0.8.13"
25
24
  spec.add_development_dependency 'rake', '~> 11.1', '>= 11.1.2'
26
- spec.add_development_dependency 'rspec', '~> 3.4', '>= 3.4.0'
25
+ spec.add_development_dependency 'rspec', '~> 3', '>= 3.0.0'
27
26
  end
@@ -43,10 +43,19 @@ RSpec.describe Redlock::Client do
43
43
  expect(@lock_info[:value]).to eq(my_lock_info[:value])
44
44
  end
45
45
 
46
- it "sets the given value when trying to extend a non-existent lock" do
47
- @lock_info = lock_manager.lock(resource_key, ttl, extend: {value: 'hello world'})
48
- expect(@lock_info).to be_lock_info_for(resource_key)
49
- expect(@lock_info[:value]).to eq('hello world') # really we should test what's in redis
46
+ context 'when extend_life flag is given' do
47
+ it 'does not extend a non-existent lock' do
48
+ @lock_info = lock_manager.lock(resource_key, ttl, extend: {value: 'hello world'}, extend_life: true)
49
+ expect(@lock_info).to eq(false)
50
+ end
51
+ end
52
+
53
+ context 'when extend_life flag is not given' do
54
+ it "sets the given value when trying to extend a non-existent lock" do
55
+ @lock_info = lock_manager.lock(resource_key, ttl, extend: {value: 'hello world'}, extend_life: false)
56
+ expect(@lock_info).to be_lock_info_for(resource_key)
57
+ expect(@lock_info[:value]).to eq('hello world') # really we should test what's in redis
58
+ end
50
59
  end
51
60
 
52
61
  it "doesn't extend somebody else's lock" do
@@ -170,40 +179,6 @@ RSpec.describe Redlock::Client do
170
179
  end
171
180
  end
172
181
 
173
- describe "extend" do
174
- context 'when lock is available' do
175
- before { @lock_info = lock_manager.lock(resource_key, ttl) }
176
- after(:each) { lock_manager.unlock(@lock_info) if @lock_info }
177
-
178
- it 'can extend its own lock' do
179
- lock_info = lock_manager.extend_life(@lock_info, ttl)
180
- expect(lock_info).to be_lock_info_for(resource_key)
181
- end
182
-
183
- it "can't extend a nonexistent lock" do
184
- lock_manager.unlock(@lock_info)
185
- lock_info = lock_manager.extend_life(@lock_info, ttl)
186
- expect(lock_info).to eq(false)
187
- end
188
- end
189
- end
190
-
191
- describe "extend!" do
192
- context 'when lock is available' do
193
- before { @lock_info = lock_manager.lock(resource_key, ttl) }
194
- after(:each) { lock_manager.unlock(@lock_info) if @lock_info }
195
-
196
- it 'can extend its own lock' do
197
- expect{ lock_manager.extend_life!(@lock_info, ttl) }.to_not raise_error
198
- end
199
-
200
- it "can't extend a nonexistent lock" do
201
- lock_manager.unlock(@lock_info)
202
- expect{ lock_manager.extend_life!(@lock_info, ttl) }.to raise_error(Redlock::LockError)
203
- end
204
- end
205
- end
206
-
207
182
  describe 'lock!' do
208
183
  context 'when lock is available' do
209
184
  it 'locks' do
@@ -226,6 +201,11 @@ RSpec.describe Redlock::Client do
226
201
  lock_manager.lock!(resource_key, ttl) { fail } rescue nil
227
202
  expect(resource_key).to be_lockable(lock_manager, ttl)
228
203
  end
204
+
205
+ it 'passes the extension parameter' do
206
+ my_lock_info = lock_manager.lock(resource_key, ttl)
207
+ expect{ lock_manager.lock!(resource_key, ttl, extend: my_lock_info){} }.to_not raise_error
208
+ end
229
209
  end
230
210
 
231
211
  context 'when lock is not available' do
@@ -3,7 +3,7 @@ require 'coveralls'
3
3
  Coveralls.wear!
4
4
  require 'redlock'
5
5
 
6
- LOCK_INFO_KEYS = %i{validity resource value}
6
+ LOCK_INFO_KEYS = [:validity, :resource, :value]
7
7
 
8
8
  RSpec::Matchers.define :be_lock_info_for do |resource|
9
9
  def correct_type?(actual)
metadata CHANGED
@@ -1,109 +1,89 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redlock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Moreira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-20 00:00:00.000000000 Z
11
+ date: 2016-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3'
20
- - - ">="
20
+ - - ! '>='
21
21
  - !ruby/object:Gem::Version
22
- version: 3.3.0
22
+ version: 3.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '3'
30
- - - ">="
30
+ - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
- version: 3.3.0
33
- - !ruby/object:Gem::Dependency
34
- name: bundler
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '1.12'
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 1.12.3
43
- type: :development
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '1.12'
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 1.12.3
32
+ version: 3.0.0
53
33
  - !ruby/object:Gem::Dependency
54
34
  name: coveralls
55
35
  requirement: !ruby/object:Gem::Requirement
56
36
  requirements:
57
- - - "~>"
37
+ - - ~>
58
38
  - !ruby/object:Gem::Version
59
39
  version: 0.8.13
60
40
  type: :development
61
41
  prerelease: false
62
42
  version_requirements: !ruby/object:Gem::Requirement
63
43
  requirements:
64
- - - "~>"
44
+ - - ~>
65
45
  - !ruby/object:Gem::Version
66
46
  version: 0.8.13
67
47
  - !ruby/object:Gem::Dependency
68
48
  name: rake
69
49
  requirement: !ruby/object:Gem::Requirement
70
50
  requirements:
71
- - - "~>"
51
+ - - ~>
72
52
  - !ruby/object:Gem::Version
73
53
  version: '11.1'
74
- - - ">="
54
+ - - ! '>='
75
55
  - !ruby/object:Gem::Version
76
56
  version: 11.1.2
77
57
  type: :development
78
58
  prerelease: false
79
59
  version_requirements: !ruby/object:Gem::Requirement
80
60
  requirements:
81
- - - "~>"
61
+ - - ~>
82
62
  - !ruby/object:Gem::Version
83
63
  version: '11.1'
84
- - - ">="
64
+ - - ! '>='
85
65
  - !ruby/object:Gem::Version
86
66
  version: 11.1.2
87
67
  - !ruby/object:Gem::Dependency
88
68
  name: rspec
89
69
  requirement: !ruby/object:Gem::Requirement
90
70
  requirements:
91
- - - "~>"
71
+ - - ~>
92
72
  - !ruby/object:Gem::Version
93
- version: '3.4'
94
- - - ">="
73
+ version: '3'
74
+ - - ! '>='
95
75
  - !ruby/object:Gem::Version
96
- version: 3.4.0
76
+ version: 3.0.0
97
77
  type: :development
98
78
  prerelease: false
99
79
  version_requirements: !ruby/object:Gem::Requirement
100
80
  requirements:
101
- - - "~>"
81
+ - - ~>
102
82
  - !ruby/object:Gem::Version
103
- version: '3.4'
104
- - - ">="
83
+ version: '3'
84
+ - - ! '>='
105
85
  - !ruby/object:Gem::Version
106
- version: 3.4.0
86
+ version: 3.0.0
107
87
  description: Distributed lock using Redis written in Ruby. Highly inspired by https://github.com/antirez/redlock-rb.
108
88
  email:
109
89
  - leandro.ribeiro.moreira@gmail.com
@@ -111,9 +91,9 @@ executables: []
111
91
  extensions: []
112
92
  extra_rdoc_files: []
113
93
  files:
114
- - ".gitignore"
115
- - ".rspec"
116
- - ".travis.yml"
94
+ - .gitignore
95
+ - .rspec
96
+ - .travis.yml
117
97
  - CONTRIBUTORS
118
98
  - Gemfile
119
99
  - Gemfile.lock
@@ -138,17 +118,17 @@ require_paths:
138
118
  - lib
139
119
  required_ruby_version: !ruby/object:Gem::Requirement
140
120
  requirements:
141
- - - ">="
121
+ - - ! '>='
142
122
  - !ruby/object:Gem::Version
143
123
  version: '0'
144
124
  required_rubygems_version: !ruby/object:Gem::Requirement
145
125
  requirements:
146
- - - ">="
126
+ - - ! '>='
147
127
  - !ruby/object:Gem::Version
148
128
  version: '0'
149
129
  requirements: []
150
130
  rubyforge_project:
151
- rubygems_version: 2.6.3
131
+ rubygems_version: 2.4.6
152
132
  signing_key:
153
133
  specification_version: 4
154
134
  summary: Distributed lock using Redis written in Ruby.