redis-client 0.9.0 → 0.11.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 +11 -0
- data/Gemfile.lock +2 -2
- data/README.md +34 -5
- data/Rakefile +10 -5
- data/lib/redis_client/config.rb +16 -2
- data/lib/redis_client/middlewares.rb +9 -2
- data/lib/redis_client/ruby_connection/resp3.rb +8 -4
- data/lib/redis_client/version.rb +1 -1
- data/lib/redis_client.rb +14 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f28d878a923f684e1ddade2a735339dc7ae55d3091b3d21b812fcf1b232b8fe
|
4
|
+
data.tar.gz: 5cc874fa373695185c4b5f040e8368be66550596838faadab8b3e57e45f8c0b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba5313f360e675d1e751f6c5138290facab7e3ea043d5328b14556050ceb44155947ad670077e22b1fb04b2aa5738a6d6b77454b5d31e0a4641c1e705f3ba545
|
7
|
+
data.tar.gz: 45463aae9b8d188cc5d1a2c0604962001bafcd266fb526fecb7ddee5081fbc28a9a5a27b8a09525b515d69266cf7740424a50408e62cf2361debe1ffb52b3d9e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 0.11.0
|
4
|
+
|
5
|
+
- hiredis: do not eagerly close the connection on read timeout, let the caller decide if a timeout is final.
|
6
|
+
- Add `Config#custom` to store configuration metadata. It can be used for per server middleware configuration.
|
7
|
+
|
8
|
+
# 0.10.0
|
9
|
+
|
10
|
+
- Added instance scoped middlewares. See: #53
|
11
|
+
- Allow subclasses of accepted types as command arguments. Fix: #51
|
12
|
+
- Improve hiredis driver error messages.
|
13
|
+
|
3
14
|
# 0.9.0
|
4
15
|
|
5
16
|
- Automatically reconnect if the process was forked.
|
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.11.0)
|
5
5
|
connection_pool
|
6
6
|
|
7
7
|
GEM
|
@@ -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.22)
|
42
42
|
toxiproxy (2.0.2)
|
43
43
|
unicode-display_width (2.2.0)
|
44
44
|
|
data/README.md
CHANGED
@@ -82,6 +82,7 @@ redis.call("GET", "mykey")
|
|
82
82
|
- `write_timeout`: The write timeout, takes precedence over the general timeout when sending commands to the server.
|
83
83
|
- `reconnect_attempts`: Specify how many times the client should retry to send queries. Defaults to `0`. Makes sure to read the [reconnection section](#reconnection) before enabling it.
|
84
84
|
- `protocol:` The version of the RESP protocol to use. Default to `3`.
|
85
|
+
- `custom`: A user owned value ignored by `redis-client` but available as `Config#custom`. This can be used to hold middleware configurations and other user specific metadatas.
|
85
86
|
|
86
87
|
### Sentinel support
|
87
88
|
|
@@ -343,12 +344,13 @@ end
|
|
343
344
|
|
344
345
|
## Production
|
345
346
|
|
346
|
-
### Instrumentation
|
347
|
+
### Instrumentation and Middlewares
|
347
348
|
|
348
|
-
`redis-client` offers a public
|
349
|
+
`redis-client` offers a public middleware API to aid in monitoring and library extension. Middleware can be registered
|
350
|
+
either globally or on a given configuration instance.
|
349
351
|
|
350
352
|
```ruby
|
351
|
-
module
|
353
|
+
module MyGlobalRedisInstrumentation
|
352
354
|
def connect(redis_config)
|
353
355
|
MyMonitoringService.instrument("redis.connect") { super }
|
354
356
|
end
|
@@ -361,11 +363,38 @@ module MyRedisInstrumentation
|
|
361
363
|
MyMonitoringService.instrument("redis.pipeline") { super }
|
362
364
|
end
|
363
365
|
end
|
364
|
-
RedisClient.register(
|
366
|
+
RedisClient.register(MyGlobalRedisInstrumentation)
|
365
367
|
```
|
366
368
|
|
367
|
-
Note that
|
369
|
+
Note that `RedisClient.register` is global and apply to all `RedisClient` instances.
|
368
370
|
|
371
|
+
To add middlewares to only a single client, you can provide them when creating the config:
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
redis_config = RedisClient.config(middlewares: [AnotherRedisInstrumentation])
|
375
|
+
redis_config.new_client
|
376
|
+
```
|
377
|
+
|
378
|
+
If middlewares need a client specific configuration, `Config#custom` can be used
|
379
|
+
|
380
|
+
```ruby
|
381
|
+
module MyGlobalRedisInstrumentation
|
382
|
+
def connect(redis_config)
|
383
|
+
MyMonitoringService.instrument("redis.connect", tags: redis_config.custom[:tags]) { super }
|
384
|
+
end
|
385
|
+
|
386
|
+
def call(command, redis_config)
|
387
|
+
MyMonitoringService.instrument("redis.query", tags: redis_config.custom[:tags]) { super }
|
388
|
+
end
|
389
|
+
|
390
|
+
def call_pipelined(commands, redis_config)
|
391
|
+
MyMonitoringService.instrument("redis.pipeline", tags: redis_config.custom[:tags]) { super }
|
392
|
+
end
|
393
|
+
end
|
394
|
+
RedisClient.register(MyGlobalRedisInstrumentation)
|
395
|
+
|
396
|
+
redis_config = RedisClient.config(custom: { tags: { "environment": Rails.env }})
|
397
|
+
```
|
369
398
|
### Timeouts
|
370
399
|
|
371
400
|
The client allows you to configure connect, read, and write timeouts.
|
data/Rakefile
CHANGED
@@ -67,12 +67,15 @@ namespace :hiredis do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
benchmark_suites = %w(single pipelined)
|
71
|
+
benchmark_modes = %i[ruby yjit hiredis]
|
70
72
|
namespace :benchmark do
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
output_path = "benchmark/#{
|
73
|
+
benchmark_suites.each do |suite|
|
74
|
+
benchmark_modes.each do |mode|
|
75
|
+
name = "#{suite}_#{mode}"
|
76
|
+
task name do
|
77
|
+
output_path = "benchmark/#{name}.md"
|
78
|
+
sh "rm", "-f", output_path
|
76
79
|
File.open(output_path, "w+") do |output|
|
77
80
|
output.puts("ruby: `#{RUBY_DESCRIPTION}`\n\n")
|
78
81
|
output.puts("redis-server: `#{`redis-server -v`.strip}`\n\n")
|
@@ -103,6 +106,8 @@ namespace :benchmark do
|
|
103
106
|
end
|
104
107
|
end
|
105
108
|
end
|
109
|
+
|
110
|
+
task all: benchmark_suites.flat_map { |s| benchmark_modes.flat_map { |m| "#{s}_#{m}" } }
|
106
111
|
end
|
107
112
|
|
108
113
|
if hiredis_supported
|
data/lib/redis_client/config.rb
CHANGED
@@ -13,7 +13,8 @@ class RedisClient
|
|
13
13
|
|
14
14
|
module Common
|
15
15
|
attr_reader :db, :password, :id, :ssl, :ssl_params, :command_builder, :inherit_socket,
|
16
|
-
:connect_timeout, :read_timeout, :write_timeout, :driver, :connection_prelude, :protocol
|
16
|
+
:connect_timeout, :read_timeout, :write_timeout, :driver, :connection_prelude, :protocol,
|
17
|
+
:middlewares_stack, :custom
|
17
18
|
|
18
19
|
alias_method :ssl?, :ssl
|
19
20
|
|
@@ -27,13 +28,15 @@ class RedisClient
|
|
27
28
|
write_timeout: timeout,
|
28
29
|
connect_timeout: timeout,
|
29
30
|
ssl: nil,
|
31
|
+
custom: {},
|
30
32
|
ssl_params: nil,
|
31
33
|
driver: nil,
|
32
34
|
protocol: 3,
|
33
35
|
client_implementation: RedisClient,
|
34
36
|
command_builder: CommandBuilder,
|
35
37
|
inherit_socket: false,
|
36
|
-
reconnect_attempts: false
|
38
|
+
reconnect_attempts: false,
|
39
|
+
middlewares: false
|
37
40
|
)
|
38
41
|
@username = username
|
39
42
|
@password = password
|
@@ -48,6 +51,8 @@ class RedisClient
|
|
48
51
|
|
49
52
|
@driver = driver ? RedisClient.driver(driver) : RedisClient.default_driver
|
50
53
|
|
54
|
+
@custom = custom
|
55
|
+
|
51
56
|
@client_implementation = client_implementation
|
52
57
|
@protocol = protocol
|
53
58
|
unless protocol == 2 || protocol == 3
|
@@ -60,6 +65,15 @@ class RedisClient
|
|
60
65
|
reconnect_attempts = Array.new(reconnect_attempts, 0).freeze if reconnect_attempts.is_a?(Integer)
|
61
66
|
@reconnect_attempts = reconnect_attempts
|
62
67
|
@connection_prelude = build_connection_prelude
|
68
|
+
|
69
|
+
middlewares_stack = Middlewares
|
70
|
+
if middlewares && !middlewares.empty?
|
71
|
+
middlewares_stack = Class.new(Middlewares)
|
72
|
+
middlewares.each do |mod|
|
73
|
+
middlewares_stack.include(mod)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
@middlewares_stack = middlewares_stack
|
63
77
|
end
|
64
78
|
|
65
79
|
def username
|
@@ -1,8 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class RedisClient
|
4
|
-
|
5
|
-
|
4
|
+
class BasicMiddleware
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
end
|
6
10
|
|
7
11
|
def connect(_config)
|
8
12
|
yield
|
@@ -13,4 +17,7 @@ class RedisClient
|
|
13
17
|
end
|
14
18
|
alias_method :call_pipelined, :call
|
15
19
|
end
|
20
|
+
|
21
|
+
class Middlewares < BasicMiddleware
|
22
|
+
end
|
16
23
|
end
|
@@ -10,12 +10,12 @@ class RedisClient
|
|
10
10
|
|
11
11
|
EOL = "\r\n".b.freeze
|
12
12
|
EOL_SIZE = EOL.bytesize
|
13
|
-
DUMP_TYPES = {
|
13
|
+
DUMP_TYPES = { # rubocop:disable Style/MutableConstant
|
14
14
|
String => :dump_string,
|
15
15
|
Symbol => :dump_symbol,
|
16
16
|
Integer => :dump_numeric,
|
17
17
|
Float => :dump_numeric,
|
18
|
-
}
|
18
|
+
}
|
19
19
|
PARSER_TYPES = {
|
20
20
|
'#' => :parse_boolean,
|
21
21
|
'$' => :parse_blob,
|
@@ -55,8 +55,12 @@ class RedisClient
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def dump_any(object, buffer)
|
58
|
-
method = DUMP_TYPES.fetch(object.class) do
|
59
|
-
|
58
|
+
method = DUMP_TYPES.fetch(object.class) do |unexpected_class|
|
59
|
+
if superclass = DUMP_TYPES.keys.find { |t| t > unexpected_class }
|
60
|
+
DUMP_TYPES[unexpected_class] = DUMP_TYPES[superclass]
|
61
|
+
else
|
62
|
+
raise TypeError, "Unsupported command argument type: #{unexpected_class}"
|
63
|
+
end
|
60
64
|
end
|
61
65
|
send(method, object, buffer)
|
62
66
|
end
|
data/lib/redis_client/version.rb
CHANGED
data/lib/redis_client.rb
CHANGED
@@ -145,7 +145,7 @@ class RedisClient
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def register(middleware)
|
148
|
-
Middlewares.
|
148
|
+
Middlewares.include(middleware)
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
@@ -153,6 +153,7 @@ class RedisClient
|
|
153
153
|
|
154
154
|
def initialize(config, **)
|
155
155
|
super
|
156
|
+
@middlewares = config.middlewares_stack.new(self)
|
156
157
|
@raw_connection = nil
|
157
158
|
@disable_reconnection = false
|
158
159
|
end
|
@@ -195,7 +196,7 @@ class RedisClient
|
|
195
196
|
def call(*command, **kwargs)
|
196
197
|
command = @command_builder.generate(command, kwargs)
|
197
198
|
result = ensure_connected do |connection|
|
198
|
-
|
199
|
+
@middlewares.call(command, config) do
|
199
200
|
connection.call(command, nil)
|
200
201
|
end
|
201
202
|
end
|
@@ -210,7 +211,7 @@ class RedisClient
|
|
210
211
|
def call_v(command)
|
211
212
|
command = @command_builder.generate(command)
|
212
213
|
result = ensure_connected do |connection|
|
213
|
-
|
214
|
+
@middlewares.call(command, config) do
|
214
215
|
connection.call(command, nil)
|
215
216
|
end
|
216
217
|
end
|
@@ -225,7 +226,7 @@ class RedisClient
|
|
225
226
|
def call_once(*command, **kwargs)
|
226
227
|
command = @command_builder.generate(command, kwargs)
|
227
228
|
result = ensure_connected(retryable: false) do |connection|
|
228
|
-
|
229
|
+
@middlewares.call(command, config) do
|
229
230
|
connection.call(command, nil)
|
230
231
|
end
|
231
232
|
end
|
@@ -240,7 +241,7 @@ class RedisClient
|
|
240
241
|
def call_once_v(command)
|
241
242
|
command = @command_builder.generate(command)
|
242
243
|
result = ensure_connected(retryable: false) do |connection|
|
243
|
-
|
244
|
+
@middlewares.call(command, config) do
|
244
245
|
connection.call(command, nil)
|
245
246
|
end
|
246
247
|
end
|
@@ -256,7 +257,7 @@ class RedisClient
|
|
256
257
|
command = @command_builder.generate(command, kwargs)
|
257
258
|
error = nil
|
258
259
|
result = ensure_connected do |connection|
|
259
|
-
|
260
|
+
@middlewares.call(command, config) do
|
260
261
|
connection.call(command, timeout)
|
261
262
|
end
|
262
263
|
rescue ReadTimeoutError => error
|
@@ -276,7 +277,7 @@ class RedisClient
|
|
276
277
|
command = @command_builder.generate(command)
|
277
278
|
error = nil
|
278
279
|
result = ensure_connected do |connection|
|
279
|
-
|
280
|
+
@middlewares.call(command, config) do
|
280
281
|
connection.call(command, timeout)
|
281
282
|
end
|
282
283
|
rescue ReadTimeoutError => error
|
@@ -347,7 +348,7 @@ class RedisClient
|
|
347
348
|
else
|
348
349
|
results = ensure_connected(retryable: pipeline._retryable?) do |connection|
|
349
350
|
commands = pipeline._commands
|
350
|
-
|
351
|
+
@middlewares.call_pipelined(commands, config) do
|
351
352
|
connection.call_pipelined(commands, pipeline._timeouts)
|
352
353
|
end
|
353
354
|
end
|
@@ -367,7 +368,7 @@ class RedisClient
|
|
367
368
|
begin
|
368
369
|
if transaction = build_transaction(&block)
|
369
370
|
commands = transaction._commands
|
370
|
-
results =
|
371
|
+
results = @middlewares.call_pipelined(commands, config) do
|
371
372
|
connection.call_pipelined(commands, nil)
|
372
373
|
end.last
|
373
374
|
else
|
@@ -386,7 +387,7 @@ class RedisClient
|
|
386
387
|
else
|
387
388
|
ensure_connected(retryable: transaction._retryable?) do |connection|
|
388
389
|
commands = transaction._commands
|
389
|
-
|
390
|
+
@middlewares.call_pipelined(commands, config) do
|
390
391
|
connection.call_pipelined(commands, nil)
|
391
392
|
end.last
|
392
393
|
end
|
@@ -649,7 +650,7 @@ class RedisClient
|
|
649
650
|
def connect
|
650
651
|
@pid = Process.pid
|
651
652
|
|
652
|
-
connection =
|
653
|
+
connection = @middlewares.connect(config) do
|
653
654
|
config.driver.new(
|
654
655
|
config,
|
655
656
|
connect_timeout: connect_timeout,
|
@@ -667,13 +668,13 @@ class RedisClient
|
|
667
668
|
# The connection prelude is deliberately not sent to Middlewares
|
668
669
|
if config.sentinel?
|
669
670
|
prelude << ["ROLE"]
|
670
|
-
role, =
|
671
|
+
role, = @middlewares.call_pipelined(prelude, config) do
|
671
672
|
connection.call_pipelined(prelude, nil).last
|
672
673
|
end
|
673
674
|
config.check_role!(role)
|
674
675
|
else
|
675
676
|
unless prelude.empty?
|
676
|
-
|
677
|
+
@middlewares.call_pipelined(prelude, config) do
|
677
678
|
connection.call_pipelined(prelude, nil)
|
678
679
|
end
|
679
680
|
end
|
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.11.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: 2022-
|
11
|
+
date: 2022-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|