redis-client 0.14.1 → 0.15.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/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+
|