redlock 1.3.2 → 2.0.0
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 +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/.gitignore +1 -0
- data/Makefile +0 -3
- data/README.md +5 -5
- data/lib/redlock/client.rb +11 -9
- data/lib/redlock/testing.rb +1 -1
- data/lib/redlock/version.rb +1 -1
- data/redlock.gemspec +1 -1
- data/spec/client_spec.rb +17 -15
- metadata +12 -19
- data/Gemfile.lock +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 679d1c44fcda7a2eaa70bdfe38c30e4ee79e417bef0b3ce064aceaf0a9cc0bbb
|
4
|
+
data.tar.gz: 48b6a41c4cc27b8ff8878647dd494a6b87e3b17e540b75d8699e32d4ee982aa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a31815a7da2fa6f5c3af35734294cdb34fdfba19dc12eaf25abe950db65be1356afc397ff29a73823d267d99d0069f86651385c1e262da6ced7541345212abda
|
7
|
+
data.tar.gz: cd4e41fe60732180b4b5f3d848715954074f8a063c1513c89e73a37311d5d4c0d8fbe1bbd92b063955324929f07bf59232040de104bfeb14d18837d297910d59
|
data/.github/workflows/ci.yml
CHANGED
data/.gitignore
CHANGED
data/Makefile
CHANGED
data/README.md
CHANGED
@@ -15,7 +15,7 @@ This is an implementation of a proposed [distributed lock algorithm with Redis](
|
|
15
15
|
|
16
16
|
## Compatibility
|
17
17
|
|
18
|
-
Redlock works with Redis versions
|
18
|
+
Redlock works with Redis versions 6.0 or later.
|
19
19
|
|
20
20
|
## Installation
|
21
21
|
|
@@ -151,7 +151,7 @@ lock_manager.get_remaining_ttl_for_lock(lock_info)
|
|
151
151
|
|
152
152
|
lock_manager.unlock(lock_info)
|
153
153
|
lock_manager.get_remaining_ttl_for_lock(lock_info)
|
154
|
-
#=> nil
|
154
|
+
#=> nil
|
155
155
|
```
|
156
156
|
|
157
157
|
Use `get_remaining_ttl_for_resource` if you do not hold a lock, but want to know the remaining TTL on a locked resource:
|
@@ -164,13 +164,13 @@ lock_info = lock_manager.lock(resource, 2000)
|
|
164
164
|
lock_manager.locked?(resource)
|
165
165
|
#=> true
|
166
166
|
lock_manager.get_remaining_ttl_for_resource(resource)
|
167
|
-
#=> 1975
|
167
|
+
#=> 1975
|
168
168
|
|
169
169
|
# Sometime later
|
170
170
|
lock_manager.locked?(resource)
|
171
171
|
#=> false
|
172
172
|
lock_manager.get_remaining_ttl_for_resource(resource)
|
173
|
-
#=> nil
|
173
|
+
#=> nil
|
174
174
|
```
|
175
175
|
|
176
176
|
## Redis client configuration
|
@@ -178,7 +178,7 @@ lock_manager.get_remaining_ttl_for_resource(resource)
|
|
178
178
|
`Redlock::Client` expects URLs or Redis objects on initialization. Redis objects should be used for configuring the connection in more detail, i.e. setting username and password.
|
179
179
|
|
180
180
|
```ruby
|
181
|
-
servers = [ 'redis://localhost:6379',
|
181
|
+
servers = [ 'redis://localhost:6379', RedisClient.new(:url => 'redis://someotherhost:6379') ]
|
182
182
|
redlock = Redlock::Client.new(servers)
|
183
183
|
```
|
184
184
|
|
data/lib/redlock/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'redis'
|
1
|
+
require 'redis-client'
|
2
2
|
require 'securerandom'
|
3
3
|
|
4
4
|
module Redlock
|
@@ -160,7 +160,7 @@ module Redlock
|
|
160
160
|
if connection.respond_to?(:client)
|
161
161
|
@redis = connection
|
162
162
|
else
|
163
|
-
@redis =
|
163
|
+
@redis = RedisClient.new(connection)
|
164
164
|
end
|
165
165
|
@redis.extend(ConnectionPoolLike)
|
166
166
|
end
|
@@ -168,13 +168,13 @@ module Redlock
|
|
168
168
|
|
169
169
|
def lock(resource, val, ttl, allow_new_lock)
|
170
170
|
recover_from_script_flush do
|
171
|
-
@redis.
|
171
|
+
@redis.call('EVALSHA', Scripts::LOCK_SCRIPT_SHA, 1, resource, val, ttl, allow_new_lock)
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
175
|
def unlock(resource, val)
|
176
176
|
recover_from_script_flush do
|
177
|
-
@redis.
|
177
|
+
@redis.call('EVALSHA', Scripts::UNLOCK_SCRIPT_SHA, 1, resource, val)
|
178
178
|
end
|
179
179
|
rescue
|
180
180
|
# Nothing to do, unlocking is just a best-effort attempt.
|
@@ -182,9 +182,9 @@ module Redlock
|
|
182
182
|
|
183
183
|
def get_remaining_ttl(resource)
|
184
184
|
recover_from_script_flush do
|
185
|
-
@redis.
|
185
|
+
@redis.call('EVALSHA', Scripts::PTTL_SCRIPT_SHA, 1, resource)
|
186
186
|
end
|
187
|
-
rescue
|
187
|
+
rescue RedisClient::ConnectionError
|
188
188
|
nil
|
189
189
|
end
|
190
190
|
|
@@ -197,8 +197,10 @@ module Redlock
|
|
197
197
|
Scripts::PTTL_SCRIPT
|
198
198
|
]
|
199
199
|
|
200
|
-
|
201
|
-
|
200
|
+
@redis.with do |connnection|
|
201
|
+
scripts.each do |script|
|
202
|
+
connnection.call('SCRIPT', 'LOAD', script)
|
203
|
+
end
|
202
204
|
end
|
203
205
|
end
|
204
206
|
|
@@ -206,7 +208,7 @@ module Redlock
|
|
206
208
|
retry_on_noscript = true
|
207
209
|
begin
|
208
210
|
yield
|
209
|
-
rescue
|
211
|
+
rescue RedisClient::CommandError => e
|
210
212
|
# When somebody has flushed the Redis instance's script cache, we might
|
211
213
|
# want to reload our scripts. Only attempt this once, though, to avoid
|
212
214
|
# going into an infinite loop.
|
data/lib/redlock/testing.rb
CHANGED
@@ -41,7 +41,7 @@ module Redlock
|
|
41
41
|
|
42
42
|
def load_scripts
|
43
43
|
load_scripts_without_testing unless Redlock::Client.testing_mode == :bypass
|
44
|
-
rescue
|
44
|
+
rescue RedisClient::CommandError
|
45
45
|
# FakeRedis doesn't have #script, but doesn't need it either.
|
46
46
|
raise unless defined?(::FakeRedis)
|
47
47
|
rescue NoMethodError
|
data/lib/redlock/version.rb
CHANGED
data/redlock.gemspec
CHANGED
@@ -18,7 +18,7 @@ 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'
|
21
|
+
spec.add_dependency 'redis-client'
|
22
22
|
|
23
23
|
spec.add_development_dependency 'connection_pool', '~> 2.2'
|
24
24
|
spec.add_development_dependency 'coveralls', '~> 0.8'
|
data/spec/client_spec.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'securerandom'
|
3
|
-
require 'redis'
|
4
3
|
require 'connection_pool'
|
5
4
|
|
6
5
|
RSpec.describe Redlock::Client do
|
7
6
|
# It is recommended to have at least 3 servers in production
|
8
7
|
let(:lock_manager_opts) { { retry_count: 3 } }
|
9
8
|
let(:lock_manager) { Redlock::Client.new(Redlock::Client::DEFAULT_REDIS_URLS, lock_manager_opts) }
|
10
|
-
let(:redis_client) {
|
9
|
+
let(:redis_client) { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") }
|
11
10
|
let(:resource_key) { SecureRandom.hex(3) }
|
12
11
|
let(:ttl) { 1000 }
|
13
12
|
let(:redis1_host) { ENV["REDIS1_HOST"] || "localhost" }
|
@@ -17,7 +16,7 @@ RSpec.describe Redlock::Client do
|
|
17
16
|
let(:redis3_host) { ENV["REDIS3_HOST"] || "127.0.0.1" }
|
18
17
|
let(:redis3_port) { ENV["REDIS3_PORT"] || "6379" }
|
19
18
|
let(:unreachable_redis) {
|
20
|
-
redis =
|
19
|
+
redis = RedisClient.new(url: 'redis://localhost:46864')
|
21
20
|
def redis.with
|
22
21
|
yield self
|
23
22
|
end
|
@@ -26,18 +25,18 @@ RSpec.describe Redlock::Client do
|
|
26
25
|
|
27
26
|
describe 'initialize' do
|
28
27
|
it 'accepts both redis URLs and Redis objects' do
|
29
|
-
servers = [ "redis://#{redis1_host}:#{redis1_port}",
|
28
|
+
servers = [ "redis://#{redis1_host}:#{redis1_port}", RedisClient.new(url: "redis://#{redis2_host}:#{redis2_port}") ]
|
30
29
|
redlock = Redlock::Client.new(servers)
|
31
30
|
|
32
31
|
redlock_servers = redlock.instance_variable_get(:@servers).map do |s|
|
33
|
-
s.instance_variable_get(:@redis).
|
32
|
+
s.instance_variable_get(:@redis).config.host
|
34
33
|
end
|
35
34
|
|
36
35
|
expect(redlock_servers).to match_array([redis1_host, redis2_host])
|
37
36
|
end
|
38
37
|
|
39
38
|
it 'accepts ConnectionPool objects' do
|
40
|
-
pool = ConnectionPool.new {
|
39
|
+
pool = ConnectionPool.new { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") }
|
41
40
|
redlock = Redlock::Client.new([pool])
|
42
41
|
|
43
42
|
lock_info = lock_manager.lock(resource_key, ttl)
|
@@ -46,12 +45,15 @@ RSpec.describe Redlock::Client do
|
|
46
45
|
end
|
47
46
|
|
48
47
|
it 'does not load scripts' do
|
49
|
-
redis_client.
|
48
|
+
redis_client.call('SCRIPT', 'FLUSH')
|
50
49
|
|
51
|
-
pool = ConnectionPool.new {
|
50
|
+
pool = ConnectionPool.new { RedisClient.new(url: "redis://#{redis1_host}:#{redis1_port}") }
|
52
51
|
redlock = Redlock::Client.new([pool])
|
53
52
|
|
54
|
-
|
53
|
+
raw_info = redis_client.call('INFO')
|
54
|
+
number_of_cached_scripts = raw_info[/number_of_cached_scripts\:\d+/].split(':').last
|
55
|
+
|
56
|
+
expect(number_of_cached_scripts).to eq("0")
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
@@ -74,7 +76,7 @@ RSpec.describe Redlock::Client do
|
|
74
76
|
it 'interprets lock time as milliseconds' do
|
75
77
|
ttl = 20000
|
76
78
|
@lock_info = lock_manager.lock(resource_key, ttl)
|
77
|
-
expect(redis_client.
|
79
|
+
expect(redis_client.call('PTTL', resource_key)).to be_within(200).of(ttl)
|
78
80
|
end
|
79
81
|
|
80
82
|
it 'can extend its own lock' do
|
@@ -106,7 +108,7 @@ RSpec.describe Redlock::Client do
|
|
106
108
|
|
107
109
|
lock_info = lock_manager.lock(resource_key, ttl, extend: lock_info, extend_only_if_locked: true)
|
108
110
|
expect(lock_info).not_to be_nil
|
109
|
-
expect(redis_client.
|
111
|
+
expect(redis_client.call('PTTL', resource_key)).to be_within(200).of(ttl)
|
110
112
|
end
|
111
113
|
|
112
114
|
context 'when extend_only_if_locked flag is not given' do
|
@@ -249,7 +251,7 @@ RSpec.describe Redlock::Client do
|
|
249
251
|
|
250
252
|
expect {
|
251
253
|
lock_manager.lock(resource_key, ttl)
|
252
|
-
}.to raise_error(
|
254
|
+
}.to raise_error(RedisClient::CannotConnectError)
|
253
255
|
end
|
254
256
|
end
|
255
257
|
|
@@ -261,7 +263,7 @@ RSpec.describe Redlock::Client do
|
|
261
263
|
redis_instance.instance_variable_set(:@redis, unreachable_redis)
|
262
264
|
expect {
|
263
265
|
lock_manager.lock(resource_key, ttl)
|
264
|
-
}.to raise_error(
|
266
|
+
}.to raise_error(RedisClient::CannotConnectError)
|
265
267
|
redis_instance.instance_variable_set(:@redis, old_redis)
|
266
268
|
expect(lock_manager.lock(resource_key, ttl)).to be_truthy
|
267
269
|
end
|
@@ -270,10 +272,10 @@ RSpec.describe Redlock::Client do
|
|
270
272
|
context 'when script cache has been flushed' do
|
271
273
|
before(:each) do
|
272
274
|
@manipulated_instance = lock_manager.instance_variable_get(:@servers).first
|
273
|
-
@manipulated_instance.instance_variable_get(:@redis).
|
275
|
+
@manipulated_instance.instance_variable_get(:@redis).call('SCRIPT', 'FLUSH')
|
274
276
|
end
|
275
277
|
|
276
|
-
it 'does not raise a
|
278
|
+
it 'does not raise a RedisClient::CommandError: NOSCRIPT error' do
|
277
279
|
expect {
|
278
280
|
lock_manager.lock(resource_key, ttl)
|
279
281
|
}.to_not raise_error
|
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redlock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leandro Moreira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: redis
|
14
|
+
name: redis-client
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '6.0'
|
19
|
+
version: '0'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '6.0'
|
26
|
+
version: '0'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: connection_pool
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,22 +96,22 @@ dependencies:
|
|
102
96
|
name: rspec
|
103
97
|
requirement: !ruby/object:Gem::Requirement
|
104
98
|
requirements:
|
105
|
-
- - "~>"
|
106
|
-
- !ruby/object:Gem::Version
|
107
|
-
version: '3'
|
108
99
|
- - ">="
|
109
100
|
- !ruby/object:Gem::Version
|
110
101
|
version: 3.0.0
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '3'
|
111
105
|
type: :development
|
112
106
|
prerelease: false
|
113
107
|
version_requirements: !ruby/object:Gem::Requirement
|
114
108
|
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '3'
|
118
109
|
- - ">="
|
119
110
|
- !ruby/object:Gem::Version
|
120
111
|
version: 3.0.0
|
112
|
+
- - "~>"
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '3'
|
121
115
|
description: Distributed lock using Redis written in Ruby. Highly inspired by https://github.com/antirez/redlock-rb.
|
122
116
|
email:
|
123
117
|
- leandro.ribeiro.moreira@gmail.com
|
@@ -130,7 +124,6 @@ files:
|
|
130
124
|
- ".rspec"
|
131
125
|
- CONTRIBUTORS
|
132
126
|
- Gemfile
|
133
|
-
- Gemfile.lock
|
134
127
|
- LICENSE
|
135
128
|
- Makefile
|
136
129
|
- README.md
|
@@ -165,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
158
|
- !ruby/object:Gem::Version
|
166
159
|
version: '0'
|
167
160
|
requirements: []
|
168
|
-
rubygems_version: 3.3.
|
161
|
+
rubygems_version: 3.0.3.1
|
169
162
|
signing_key:
|
170
163
|
specification_version: 4
|
171
164
|
summary: Distributed lock using Redis written in Ruby.
|
data/Gemfile.lock
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
redlock (1.3.2)
|
5
|
-
redis (>= 3.0.0, < 6.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
connection_pool (2.3.0)
|
11
|
-
coveralls (0.8.23)
|
12
|
-
json (>= 1.8, < 3)
|
13
|
-
simplecov (~> 0.16.1)
|
14
|
-
term-ansicolor (~> 1.3)
|
15
|
-
thor (>= 0.19.4, < 2.0)
|
16
|
-
tins (~> 1.6)
|
17
|
-
diff-lcs (1.5.0)
|
18
|
-
docile (1.4.0)
|
19
|
-
json (2.3.1)
|
20
|
-
rake (13.0.6)
|
21
|
-
redis (5.0.5)
|
22
|
-
redis-client (>= 0.9.0)
|
23
|
-
redis-client (0.10.0)
|
24
|
-
connection_pool
|
25
|
-
rspec (3.11.0)
|
26
|
-
rspec-core (~> 3.11.0)
|
27
|
-
rspec-expectations (~> 3.11.0)
|
28
|
-
rspec-mocks (~> 3.11.0)
|
29
|
-
rspec-core (3.11.0)
|
30
|
-
rspec-support (~> 3.11.0)
|
31
|
-
rspec-expectations (3.11.1)
|
32
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
-
rspec-support (~> 3.11.0)
|
34
|
-
rspec-mocks (3.11.1)
|
35
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
-
rspec-support (~> 3.11.0)
|
37
|
-
rspec-support (3.11.1)
|
38
|
-
simplecov (0.16.1)
|
39
|
-
docile (~> 1.1)
|
40
|
-
json (>= 1.8, < 3)
|
41
|
-
simplecov-html (~> 0.10.0)
|
42
|
-
simplecov-html (0.10.2)
|
43
|
-
sync (0.5.0)
|
44
|
-
term-ansicolor (1.7.1)
|
45
|
-
tins (~> 1.0)
|
46
|
-
thor (1.2.1)
|
47
|
-
tins (1.31.1)
|
48
|
-
sync
|
49
|
-
|
50
|
-
PLATFORMS
|
51
|
-
ruby
|
52
|
-
|
53
|
-
DEPENDENCIES
|
54
|
-
connection_pool (~> 2.2)
|
55
|
-
coveralls (~> 0.8)
|
56
|
-
json (~> 2.3.1, >= 2.3.0)
|
57
|
-
rake (~> 13.0, >= 11.1.2)
|
58
|
-
redlock!
|
59
|
-
rspec (~> 3, >= 3.0.0)
|
60
|
-
|
61
|
-
BUNDLED WITH
|
62
|
-
2.3.7
|