redis-client 0.14.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +4 -4
- data/README.md +6 -0
- data/lib/redis_client/config.rb +11 -27
- data/lib/redis_client/ruby_connection/buffered_io.rb +4 -0
- data/lib/redis_client/ruby_connection.rb +13 -0
- data/lib/redis_client/sentinel_config.rb +21 -5
- data/lib/redis_client/url_config.rb +53 -0
- data/lib/redis_client/version.rb +1 -1
- data/lib/redis_client.rb +15 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa81349f7f830db128f2637bc4c782543b9c51a16075b54fdc4700810a95ae83
|
4
|
+
data.tar.gz: d34e19d6229292bb6b15e61aebeda57729780040e098f0fae1beb534f9717ff9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01ed887cfc90ffc36ff82669a459d1c9b13b72c9d81f66ca770e7642c16cba90d30cfd31768029b81a1519778f6af2905b145ab606f070008ac471192ce812fa
|
7
|
+
data.tar.gz: 64320bfdcdaa3fd4402ae41350dc0451127f895e3f224d916140ea3fc5813dfe9344f04dc18c20d82e9c3a0878d19ade9b3716274278a21fbe3fd1c5da855797
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 0.15.0
|
4
|
+
|
5
|
+
- Discard sockets rather than explictly close them when a fork is detected. #126.
|
6
|
+
- Allow to configure sentinel client via url. #117.
|
7
|
+
- Fix sentinel to preverse the auth/password when refreshing the sentinel list. #107.
|
8
|
+
|
3
9
|
# 0.14.1
|
4
10
|
|
5
11
|
- Include the timeout value in TimeoutError messages.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
redis-client (0.
|
4
|
+
redis-client (0.15.0)
|
5
5
|
connection_pool
|
6
6
|
|
7
7
|
GEM
|
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
ast (2.4.2)
|
11
11
|
benchmark-ips (2.12.0)
|
12
12
|
byebug (11.1.3)
|
13
|
-
connection_pool (2.4.
|
13
|
+
connection_pool (2.4.1)
|
14
14
|
hiredis (0.6.3)
|
15
15
|
hiredis (0.6.3-java)
|
16
16
|
minitest (5.15.0)
|
@@ -19,7 +19,7 @@ GEM
|
|
19
19
|
ast (~> 2.4.1)
|
20
20
|
rainbow (3.1.1)
|
21
21
|
rake (13.0.6)
|
22
|
-
rake-compiler (1.2.
|
22
|
+
rake-compiler (1.2.3)
|
23
23
|
rake
|
24
24
|
redis (4.6.0)
|
25
25
|
regexp_parser (2.5.0)
|
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
rubocop-minitest (0.19.1)
|
39
39
|
rubocop (>= 0.90, < 2.0)
|
40
40
|
ruby-progressbar (1.11.0)
|
41
|
-
stackprof (0.2.
|
41
|
+
stackprof (0.2.25)
|
42
42
|
toxiproxy (2.0.2)
|
43
43
|
unicode-display_width (2.2.0)
|
44
44
|
|
data/README.md
CHANGED
@@ -343,6 +343,10 @@ loop do
|
|
343
343
|
end
|
344
344
|
```
|
345
345
|
|
346
|
+
*Note*: pubsub connections are stateful, as such they won't ever reconnect automatically.
|
347
|
+
The caller is resonsible for reconnecting if the connection is lost and to resubscribe to
|
348
|
+
all channels.
|
349
|
+
|
346
350
|
## Production
|
347
351
|
|
348
352
|
### Instrumentation and Middlewares
|
@@ -439,6 +443,8 @@ redis.call("GET", "counter") # Will be retried up to 3 times.
|
|
439
443
|
redis.call_once("INCR", "counter") # Won't be retried.
|
440
444
|
```
|
441
445
|
|
446
|
+
**Note**: automatic reconnection doesn't apply to pubsub clients as their connection is stateful.
|
447
|
+
|
442
448
|
### Exponential backoff
|
443
449
|
|
444
450
|
Alternatively, `reconnect_attempts` accepts a list of sleep durations for implementing exponential backoff:
|
data/lib/redis_client/config.rb
CHANGED
@@ -162,37 +162,21 @@ class RedisClient
|
|
162
162
|
**kwargs
|
163
163
|
)
|
164
164
|
if url
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
kwargs[:password] ||= if uri.user && !uri.password
|
175
|
-
URI.decode_www_form_component(uri.user)
|
176
|
-
elsif uri.user && uri.password
|
177
|
-
URI.decode_www_form_component(uri.password)
|
178
|
-
end
|
179
|
-
|
180
|
-
db_path = uri.path&.delete_prefix("/")
|
181
|
-
kwargs[:db] ||= Integer(db_path) if db_path && !db_path.empty?
|
165
|
+
url_config = URLConfig.new(url)
|
166
|
+
kwargs = {
|
167
|
+
ssl: url_config.ssl?,
|
168
|
+
username: url_config.username,
|
169
|
+
password: url_config.password,
|
170
|
+
db: url_config.db,
|
171
|
+
}.compact.merge(kwargs)
|
172
|
+
host ||= url_config.host
|
173
|
+
port ||= url_config.port
|
182
174
|
end
|
183
175
|
|
184
176
|
super(**kwargs)
|
185
177
|
|
186
|
-
@host = host
|
187
|
-
|
188
|
-
uri_host = uri&.host
|
189
|
-
uri_host = nil if uri_host&.empty?
|
190
|
-
if uri_host
|
191
|
-
@host = uri_host&.sub(/\A\[(.*)\]\z/, '\1')
|
192
|
-
end
|
193
|
-
end
|
194
|
-
@host ||= DEFAULT_HOST
|
195
|
-
@port = Integer(port || uri&.port || DEFAULT_PORT)
|
178
|
+
@host = host || DEFAULT_HOST
|
179
|
+
@port = Integer(port || DEFAULT_PORT)
|
196
180
|
@path = path
|
197
181
|
end
|
198
182
|
end
|
@@ -58,6 +58,13 @@ class RedisClient
|
|
58
58
|
super
|
59
59
|
end
|
60
60
|
|
61
|
+
def discard
|
62
|
+
unless @io.closed?
|
63
|
+
@io.reopen(File::NULL)
|
64
|
+
end
|
65
|
+
close
|
66
|
+
end
|
67
|
+
|
61
68
|
def read_timeout=(timeout)
|
62
69
|
@read_timeout = timeout
|
63
70
|
@io.read_timeout = timeout if @io
|
@@ -101,6 +108,12 @@ class RedisClient
|
|
101
108
|
raise ConnectionError, error.message
|
102
109
|
end
|
103
110
|
|
111
|
+
def measure_round_trip_delay
|
112
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
113
|
+
call(["PING"], @read_timeout)
|
114
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start
|
115
|
+
end
|
116
|
+
|
104
117
|
private
|
105
118
|
|
106
119
|
def connect
|
@@ -7,11 +7,28 @@ class RedisClient
|
|
7
7
|
SENTINEL_DELAY = 0.25
|
8
8
|
DEFAULT_RECONNECT_ATTEMPTS = 2
|
9
9
|
|
10
|
-
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(sentinels:, role: :master, name: nil, url: nil, **client_config)
|
11
13
|
unless %i(master replica slave).include?(role)
|
12
14
|
raise ArgumentError, "Expected role to be either :master or :replica, got: #{role.inspect}"
|
13
15
|
end
|
14
16
|
|
17
|
+
if url
|
18
|
+
url_config = URLConfig.new(url)
|
19
|
+
client_config = {
|
20
|
+
username: url_config.username,
|
21
|
+
password: url_config.password,
|
22
|
+
db: url_config.db,
|
23
|
+
}.compact.merge(client_config)
|
24
|
+
name ||= url_config.host
|
25
|
+
end
|
26
|
+
|
27
|
+
@name = name
|
28
|
+
unless @name
|
29
|
+
raise ArgumentError, "RedisClient::SentinelConfig requires either a name or an url with a host"
|
30
|
+
end
|
31
|
+
|
15
32
|
@to_list_of_hash = @to_hash = nil
|
16
33
|
@extra_config = {}
|
17
34
|
if client_config[:protocol] == 2
|
@@ -25,8 +42,6 @@ class RedisClient
|
|
25
42
|
end
|
26
43
|
end
|
27
44
|
|
28
|
-
@name = name
|
29
|
-
@sentinel_configs = sentinels_to_configs(sentinels)
|
30
45
|
@sentinels = {}.compare_by_identity
|
31
46
|
@role = role
|
32
47
|
@mutex = Mutex.new
|
@@ -35,6 +50,7 @@ class RedisClient
|
|
35
50
|
client_config[:reconnect_attempts] ||= DEFAULT_RECONNECT_ATTEMPTS
|
36
51
|
@client_config = client_config || {}
|
37
52
|
super(**client_config)
|
53
|
+
@sentinel_configs = sentinels_to_configs(sentinels)
|
38
54
|
end
|
39
55
|
|
40
56
|
def sentinels
|
@@ -90,9 +106,9 @@ class RedisClient
|
|
90
106
|
sentinels.map do |sentinel|
|
91
107
|
case sentinel
|
92
108
|
when String
|
93
|
-
Config.new(**@extra_config, url: sentinel)
|
109
|
+
Config.new(**@client_config, **@extra_config, url: sentinel, db: nil)
|
94
110
|
else
|
95
|
-
Config.new(**@extra_config, **sentinel)
|
111
|
+
Config.new(**@client_config, **@extra_config, **sentinel, db: nil)
|
96
112
|
end
|
97
113
|
end
|
98
114
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
class RedisClient
|
6
|
+
class URLConfig
|
7
|
+
DEFAULT_SCHEMA = "redis"
|
8
|
+
SSL_SCHEMA = "rediss"
|
9
|
+
|
10
|
+
attr_reader :url, :uri
|
11
|
+
|
12
|
+
def initialize(url)
|
13
|
+
@url = url
|
14
|
+
@uri = URI(url)
|
15
|
+
unless uri.scheme == DEFAULT_SCHEMA || uri.scheme == SSL_SCHEMA
|
16
|
+
raise ArgumentError, "Invalid URL: #{url.inspect}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def ssl?
|
21
|
+
@uri.scheme == SSL_SCHEMA
|
22
|
+
end
|
23
|
+
|
24
|
+
def db
|
25
|
+
db_path = uri.path&.delete_prefix("/")
|
26
|
+
Integer(db_path) if db_path && !db_path.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def username
|
30
|
+
uri.user if uri.password && !uri.user.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def password
|
34
|
+
if uri.user && !uri.password
|
35
|
+
URI.decode_www_form_component(uri.user)
|
36
|
+
elsif uri.user && uri.password
|
37
|
+
URI.decode_www_form_component(uri.password)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def host
|
42
|
+
return if uri.host.nil? || uri.host.empty?
|
43
|
+
|
44
|
+
uri.host.sub(/\A\[(.*)\]\z/, '\1')
|
45
|
+
end
|
46
|
+
|
47
|
+
def port
|
48
|
+
return unless uri.port
|
49
|
+
|
50
|
+
Integer(uri.port)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/redis_client/version.rb
CHANGED
data/lib/redis_client.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "redis_client/version"
|
4
4
|
require "redis_client/command_builder"
|
5
|
+
require "redis_client/url_config"
|
5
6
|
require "redis_client/config"
|
6
7
|
require "redis_client/pid_cache"
|
7
8
|
require "redis_client/sentinel_config"
|
@@ -204,6 +205,14 @@ class RedisClient
|
|
204
205
|
sub
|
205
206
|
end
|
206
207
|
|
208
|
+
def measure_round_trip_delay
|
209
|
+
ensure_connected do |connection|
|
210
|
+
@middlewares.call(["PING"], config) do
|
211
|
+
connection.measure_round_trip_delay
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
207
216
|
def call(*command, **kwargs)
|
208
217
|
command = @command_builder.generate(command, kwargs)
|
209
218
|
result = ensure_connected do |connection|
|
@@ -349,6 +358,11 @@ class RedisClient
|
|
349
358
|
self
|
350
359
|
end
|
351
360
|
|
361
|
+
def discard
|
362
|
+
@raw_connection&.discard
|
363
|
+
self
|
364
|
+
end
|
365
|
+
|
352
366
|
def pipelined
|
353
367
|
pipeline = Pipeline.new(@command_builder)
|
354
368
|
yield pipeline
|
@@ -609,7 +623,7 @@ class RedisClient
|
|
609
623
|
end
|
610
624
|
|
611
625
|
def ensure_connected(retryable: true)
|
612
|
-
|
626
|
+
discard if !config.inherit_socket && @pid != PIDCache.pid
|
613
627
|
|
614
628
|
if @disable_reconnection
|
615
629
|
if block_given?
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- lib/redis_client/ruby_connection/buffered_io.rb
|
52
52
|
- lib/redis_client/ruby_connection/resp3.rb
|
53
53
|
- lib/redis_client/sentinel_config.rb
|
54
|
+
- lib/redis_client/url_config.rb
|
54
55
|
- lib/redis_client/version.rb
|
55
56
|
- redis-client.gemspec
|
56
57
|
homepage: https://github.com/redis-rb/redis-client
|
@@ -76,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
77
|
- !ruby/object:Gem::Version
|
77
78
|
version: '0'
|
78
79
|
requirements: []
|
79
|
-
rubygems_version: 3.
|
80
|
+
rubygems_version: 3.3.7
|
80
81
|
signing_key:
|
81
82
|
specification_version: 4
|
82
83
|
summary: Simple low-level client for Redis 6+
|