redis-client 0.5.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/Gemfile.lock +1 -1
- data/README.md +12 -1
- data/Rakefile +2 -2
- data/lib/redis_client/command_builder.rb +4 -8
- data/lib/redis_client/config.rb +30 -11
- data/lib/redis_client/decorator.rb +2 -2
- data/lib/redis_client/pooled.rb +1 -1
- data/lib/redis_client/ruby_connection/resp3.rb +11 -7
- data/lib/redis_client/ruby_connection.rb +5 -5
- data/lib/redis_client/sentinel_config.rb +27 -5
- data/lib/redis_client/version.rb +1 -1
- data/lib/redis_client.rb +121 -32
- 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: 2b3a285f6dbfb718f7fa429e962dbb955f3109cf67d785869076c8f0407d7d45
|
4
|
+
data.tar.gz: e7e56c056e9eaabc96e438474c70bd2a3ff46a386c28cc891c4b13acbd255492
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f70dfa045ca15360ba86f18cfa278a98296531b20b661a39abc8788091ff34f5407ec084e48fac45e1a2362f9741512ab35bfcc93d3fd16b3170fd188c57373
|
7
|
+
data.tar.gz: eee07f8f34ba002f46201e50d2d72ff6f05192ccaa06ae23e952bde1008f2b33783afda48ac37ad70d512619395ac442d129d305adf78c17eced954edd9922fa
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 0.6.2
|
4
|
+
|
5
|
+
- Fix sentinel to not connected to s_down or o_down replicas.
|
6
|
+
|
7
|
+
# 0.6.1
|
8
|
+
|
9
|
+
- Fix `REDIS_REPLY_SET` parsing in `hiredis`.
|
10
|
+
|
11
|
+
# 0.6.0
|
12
|
+
|
13
|
+
- Added `protocol: 2` options to talk with Redis 5 and older servers.
|
14
|
+
- Added `_v` versions of `call` methods to make it easier to pass commands as arrays without splating.
|
15
|
+
- Fix calling `blocking_call` with a block in a pipeline.
|
16
|
+
- `blocking_call` now raise `ReadTimeoutError` if the command didn't complete in time.
|
17
|
+
- Fix `blocking_call` to not respect `retry_attempts` on timeout.
|
18
|
+
- Stop parsing RESP3 sets as Ruby Set instances.
|
19
|
+
- Fix `SystemStackError` when parsing very large hashes. Fix: #30
|
20
|
+
- `hiredis` now more properly release the GVL when doing IOs.
|
21
|
+
|
3
22
|
# 0.5.1
|
4
23
|
|
5
24
|
- Fix a regression in the `scan` familly of methods, they would raise with `ArgumentError: can't issue an empty redis command`. Fix: #24
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -81,6 +81,7 @@ redis.call("GET", "mykey")
|
|
81
81
|
- `read_timeout`: The read timeout, takes precedence over the general timeout when reading responses from the server.
|
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
|
+
- `protocol:` The version of the RESP protocol to use. Default to `3`.
|
84
85
|
|
85
86
|
### Sentinel support
|
86
87
|
|
@@ -207,6 +208,16 @@ redis.call("EXISTS", "counter") # => 1
|
|
207
208
|
redis.call("EXISTS", "counter") { |c| c > 0 } # => true
|
208
209
|
```
|
209
210
|
|
211
|
+
### `*_v` methods
|
212
|
+
|
213
|
+
In some it's more convenient to pass commands as arrays, for that `_v` versions of `call` methods are available.
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
redis.call_v(["MGET"] + keys)
|
217
|
+
redis.blocking_call_v(1, ["MGET"] + keys)
|
218
|
+
redis.call_once_v(1, ["MGET"] + keys)
|
219
|
+
```
|
220
|
+
|
210
221
|
### Blocking commands
|
211
222
|
|
212
223
|
For blocking commands such as `BRPOP`, a custom timeout duration can be passed as first argument of the `#blocking_call` method:
|
@@ -215,7 +226,7 @@ For blocking commands such as `BRPOP`, a custom timeout duration can be passed a
|
|
215
226
|
redis.blocking_call(timeout, "BRPOP", "key", 0)
|
216
227
|
```
|
217
228
|
|
218
|
-
If `timeout` is reached, `#blocking_call`
|
229
|
+
If `timeout` is reached, `#blocking_call` raises `RedisClient::ReadTimeoutError` and doesn't retry regardless of the `reconnect_attempts` configuration.
|
219
230
|
|
220
231
|
`timeout` is expressed in seconds, you can pass `false` or `0` to mean no timeout.
|
221
232
|
|
data/Rakefile
CHANGED
@@ -107,8 +107,8 @@ end
|
|
107
107
|
|
108
108
|
if hiredis_supported
|
109
109
|
task default: %i[compile test rubocop]
|
110
|
-
task ci: %i[compile test]
|
110
|
+
task ci: %i[compile test:ruby test:hiredis]
|
111
111
|
else
|
112
112
|
task default: %i[test rubocop]
|
113
|
-
task ci: %i[test]
|
113
|
+
task ci: %i[test:ruby]
|
114
114
|
end
|
@@ -5,19 +5,17 @@ class RedisClient
|
|
5
5
|
extend self
|
6
6
|
|
7
7
|
if Symbol.method_defined?(:name)
|
8
|
-
def generate
|
8
|
+
def generate(args, kwargs = nil)
|
9
9
|
command = args.flat_map do |element|
|
10
10
|
case element
|
11
11
|
when Hash
|
12
12
|
element.flatten
|
13
|
-
when Set
|
14
|
-
element.to_a
|
15
13
|
else
|
16
14
|
element
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
|
-
kwargs
|
18
|
+
kwargs&.each do |key, value|
|
21
19
|
if value
|
22
20
|
if value == true
|
23
21
|
command << key.name
|
@@ -47,19 +45,17 @@ class RedisClient
|
|
47
45
|
command
|
48
46
|
end
|
49
47
|
else
|
50
|
-
def generate
|
48
|
+
def generate(args, kwargs = nil)
|
51
49
|
command = args.flat_map do |element|
|
52
50
|
case element
|
53
51
|
when Hash
|
54
52
|
element.flatten
|
55
|
-
when Set
|
56
|
-
element.to_a
|
57
53
|
else
|
58
54
|
element
|
59
55
|
end
|
60
56
|
end
|
61
57
|
|
62
|
-
kwargs
|
58
|
+
kwargs&.each do |key, value|
|
63
59
|
if value
|
64
60
|
if value == true
|
65
61
|
command << key.to_s
|
data/lib/redis_client/config.rb
CHANGED
@@ -12,8 +12,8 @@ class RedisClient
|
|
12
12
|
DEFAULT_DB = 0
|
13
13
|
|
14
14
|
module Common
|
15
|
-
attr_reader :db, :
|
16
|
-
:connect_timeout, :read_timeout, :write_timeout, :driver, :connection_prelude
|
15
|
+
attr_reader :db, :password, :id, :ssl, :ssl_params, :command_builder,
|
16
|
+
:connect_timeout, :read_timeout, :write_timeout, :driver, :connection_prelude, :protocol
|
17
17
|
|
18
18
|
alias_method :ssl?, :ssl
|
19
19
|
|
@@ -29,10 +29,12 @@ class RedisClient
|
|
29
29
|
ssl: nil,
|
30
30
|
ssl_params: nil,
|
31
31
|
driver: nil,
|
32
|
+
protocol: 3,
|
33
|
+
client_implementation: RedisClient,
|
32
34
|
command_builder: CommandBuilder,
|
33
35
|
reconnect_attempts: false
|
34
36
|
)
|
35
|
-
@username = username
|
37
|
+
@username = username
|
36
38
|
@password = password
|
37
39
|
@db = db || DEFAULT_DB
|
38
40
|
@id = id
|
@@ -45,14 +47,23 @@ class RedisClient
|
|
45
47
|
|
46
48
|
@driver = driver ? RedisClient.driver(driver) : RedisClient.default_driver
|
47
49
|
|
50
|
+
@client_implementation = client_implementation
|
51
|
+
@protocol = protocol
|
52
|
+
unless protocol == 2 || protocol == 3
|
53
|
+
raise ArgumentError, "Unknown protocol version #{protocol.inspect}, expected 2 or 3"
|
54
|
+
end
|
55
|
+
|
48
56
|
@command_builder = command_builder
|
49
57
|
|
50
58
|
reconnect_attempts = Array.new(reconnect_attempts, 0).freeze if reconnect_attempts.is_a?(Integer)
|
51
59
|
@reconnect_attempts = reconnect_attempts
|
52
|
-
|
53
60
|
@connection_prelude = build_connection_prelude
|
54
61
|
end
|
55
62
|
|
63
|
+
def username
|
64
|
+
@username || DEFAULT_USERNAME
|
65
|
+
end
|
66
|
+
|
56
67
|
def sentinel?
|
57
68
|
false
|
58
69
|
end
|
@@ -63,7 +74,7 @@ class RedisClient
|
|
63
74
|
end
|
64
75
|
|
65
76
|
def new_client(**kwargs)
|
66
|
-
|
77
|
+
@client_implementation.new(self, **kwargs)
|
67
78
|
end
|
68
79
|
|
69
80
|
def retry_connecting?(attempt, _error)
|
@@ -79,7 +90,7 @@ class RedisClient
|
|
79
90
|
end
|
80
91
|
|
81
92
|
def ssl_context
|
82
|
-
@ssl_context ||= @driver.ssl_context(@ssl_params)
|
93
|
+
@ssl_context ||= @driver.ssl_context(@ssl_params || {})
|
83
94
|
end
|
84
95
|
|
85
96
|
def server_url
|
@@ -94,10 +105,18 @@ class RedisClient
|
|
94
105
|
|
95
106
|
def build_connection_prelude
|
96
107
|
prelude = []
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
108
|
+
if protocol == 3
|
109
|
+
prelude << if @password
|
110
|
+
["HELLO", "3", "AUTH", @username || DEFAULT_USERNAME, @password]
|
111
|
+
else
|
112
|
+
["HELLO", "3"]
|
113
|
+
end
|
114
|
+
elsif @password
|
115
|
+
prelude << if @username && !@username.empty?
|
116
|
+
["AUTH", @username, @password]
|
117
|
+
else
|
118
|
+
["AUTH", @password]
|
119
|
+
end
|
101
120
|
end
|
102
121
|
|
103
122
|
if @db && @db != 0
|
@@ -136,7 +155,7 @@ class RedisClient
|
|
136
155
|
super(**kwargs)
|
137
156
|
|
138
157
|
@host = host || uri&.host&.sub(/\A\[(.*)\]\z/, '\1') || DEFAULT_HOST
|
139
|
-
@port = port || uri&.port || DEFAULT_PORT
|
158
|
+
@port = Integer(port || uri&.port || DEFAULT_PORT)
|
140
159
|
@path = path
|
141
160
|
end
|
142
161
|
end
|
@@ -20,7 +20,7 @@ class RedisClient
|
|
20
20
|
@client = client
|
21
21
|
end
|
22
22
|
|
23
|
-
%i(call call_once blocking_call).each do |method|
|
23
|
+
%i(call call_v call_once call_once_v blocking_call blocking_call_v).each do |method|
|
24
24
|
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
25
25
|
def #{method}(*args, &block)
|
26
26
|
@client.#{method}(*args, &block)
|
@@ -64,7 +64,7 @@ class RedisClient
|
|
64
64
|
RUBY
|
65
65
|
end
|
66
66
|
|
67
|
-
%i(id config size connect_timeout read_timeout write_timeout).each do |reader|
|
67
|
+
%i(id config size connect_timeout read_timeout write_timeout pubsub).each do |reader|
|
68
68
|
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
69
69
|
def #{reader}
|
70
70
|
@client.#{reader}
|
data/lib/redis_client/pooled.rb
CHANGED
@@ -49,7 +49,7 @@ class RedisClient
|
|
49
49
|
pool.size
|
50
50
|
end
|
51
51
|
|
52
|
-
methods = %w(pipelined multi pubsub call call_once blocking_call)
|
52
|
+
methods = %w(pipelined multi pubsub call call_v call_once call_once_v blocking_call blocking_call_v)
|
53
53
|
iterable_methods = %w(scan sscan hscan zscan)
|
54
54
|
begin
|
55
55
|
methods.each do |method|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
|
-
|
5
3
|
class RedisClient
|
6
4
|
module RESP3
|
7
5
|
module_function
|
@@ -41,8 +39,6 @@ class RedisClient
|
|
41
39
|
case element
|
42
40
|
when Hash
|
43
41
|
element.flatten
|
44
|
-
when Set
|
45
|
-
element.to_a
|
46
42
|
else
|
47
43
|
element
|
48
44
|
end
|
@@ -55,7 +51,7 @@ class RedisClient
|
|
55
51
|
end
|
56
52
|
|
57
53
|
def new_buffer
|
58
|
-
String.new(encoding: Encoding::BINARY, capacity:
|
54
|
+
String.new(encoding: Encoding::BINARY, capacity: 127)
|
59
55
|
end
|
60
56
|
|
61
57
|
def dump_any(object, buffer)
|
@@ -144,11 +140,15 @@ class RedisClient
|
|
144
140
|
end
|
145
141
|
|
146
142
|
def parse_set(io)
|
147
|
-
parse_sequence(io, parse_integer(io))
|
143
|
+
parse_sequence(io, parse_integer(io))
|
148
144
|
end
|
149
145
|
|
150
146
|
def parse_map(io)
|
151
|
-
|
147
|
+
hash = {}
|
148
|
+
parse_integer(io).times do
|
149
|
+
hash[parse(io)] = parse(io)
|
150
|
+
end
|
151
|
+
hash
|
152
152
|
end
|
153
153
|
|
154
154
|
def parse_push(io)
|
@@ -156,6 +156,8 @@ class RedisClient
|
|
156
156
|
end
|
157
157
|
|
158
158
|
def parse_sequence(io, size)
|
159
|
+
return if size < 0 # RESP2 nil
|
160
|
+
|
159
161
|
array = Array.new(size)
|
160
162
|
size.times do |index|
|
161
163
|
array[index] = parse(io)
|
@@ -185,6 +187,8 @@ class RedisClient
|
|
185
187
|
|
186
188
|
def parse_blob(io)
|
187
189
|
bytesize = parse_integer(io)
|
190
|
+
return if bytesize < 0 # RESP2 nil type
|
191
|
+
|
188
192
|
str = io.read_chomp(bytesize)
|
189
193
|
str.force_encoding(Encoding.default_external)
|
190
194
|
str.force_encoding(Encoding::BINARY) unless str.valid_encoding?
|
@@ -60,9 +60,9 @@ class RedisClient
|
|
60
60
|
loop do
|
61
61
|
case status = socket.connect_nonblock(exception: false)
|
62
62
|
when :wait_readable
|
63
|
-
socket.to_io.wait_readable(connect_timeout) or raise
|
63
|
+
socket.to_io.wait_readable(connect_timeout) or raise CannotConnectError
|
64
64
|
when :wait_writable
|
65
|
-
socket.to_io.wait_writable(connect_timeout) or raise
|
65
|
+
socket.to_io.wait_writable(connect_timeout) or raise CannotConnectError
|
66
66
|
when socket
|
67
67
|
break
|
68
68
|
else
|
@@ -76,10 +76,8 @@ class RedisClient
|
|
76
76
|
read_timeout: read_timeout,
|
77
77
|
write_timeout: write_timeout,
|
78
78
|
)
|
79
|
-
rescue Errno::ETIMEDOUT => error
|
80
|
-
raise ConnectTimeoutError, error.message
|
81
79
|
rescue SystemCallError, OpenSSL::SSL::SSLError, SocketError => error
|
82
|
-
raise
|
80
|
+
raise CannotConnectError, error.message, error.backtrace
|
83
81
|
end
|
84
82
|
|
85
83
|
def connected?
|
@@ -125,6 +123,8 @@ class RedisClient
|
|
125
123
|
else
|
126
124
|
@io.with_timeout(timeout) { RESP3.load(@io) }
|
127
125
|
end
|
126
|
+
rescue RedisClient::RESP3::UnknownType => error
|
127
|
+
raise RedisClient::ProtocolError, error.message
|
128
128
|
rescue SystemCallError, IOError, OpenSSL::SSL::SSLError => error
|
129
129
|
raise ConnectionError, error.message
|
130
130
|
end
|
@@ -12,8 +12,21 @@ class RedisClient
|
|
12
12
|
raise ArgumentError, "Expected role to be either :master or :replica, got: #{role.inspect}"
|
13
13
|
end
|
14
14
|
|
15
|
+
@to_list_of_hash = @to_hash = nil
|
16
|
+
extra_config = {}
|
17
|
+
if client_config[:protocol] == 2
|
18
|
+
extra_config[:protocol] = client_config[:protocol]
|
19
|
+
@to_list_of_hash = lambda do |may_be_a_list|
|
20
|
+
if may_be_a_list.is_a?(Array)
|
21
|
+
may_be_a_list.map { |l| l.each_slice(2).to_h }
|
22
|
+
else
|
23
|
+
may_be_a_list
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
15
28
|
@name = name
|
16
|
-
@sentinel_configs = sentinels.map { |s| Config.new(**s) }
|
29
|
+
@sentinel_configs = sentinels.map { |s| Config.new(**extra_config, **s) }
|
17
30
|
@sentinels = {}.compare_by_identity
|
18
31
|
@role = role
|
19
32
|
@mutex = Mutex.new
|
@@ -90,7 +103,10 @@ class RedisClient
|
|
90
103
|
return Config.new(host: host, port: Integer(port), **@client_config)
|
91
104
|
end
|
92
105
|
end
|
93
|
-
|
106
|
+
rescue ConnectionError
|
107
|
+
raise ConnectionError, "No sentinels available"
|
108
|
+
else
|
109
|
+
raise ConnectionError, "Couldn't locate a replica for role: #{@name}"
|
94
110
|
end
|
95
111
|
|
96
112
|
def sentinel_client(sentinel_config)
|
@@ -99,13 +115,19 @@ class RedisClient
|
|
99
115
|
|
100
116
|
def resolve_replica
|
101
117
|
each_sentinel do |sentinel_client|
|
102
|
-
replicas = sentinel_client.call("SENTINEL", "replicas", @name)
|
118
|
+
replicas = sentinel_client.call("SENTINEL", "replicas", @name, &@to_list_of_hash)
|
119
|
+
replicas.reject! do |r|
|
120
|
+
flags = r["flags"].to_s.split(",")
|
121
|
+
flags.include?("s_down") || flags.include?("o_down")
|
122
|
+
end
|
103
123
|
next if replicas.empty?
|
104
124
|
|
105
|
-
replica = replicas.
|
106
|
-
replica ||= replicas.sample
|
125
|
+
replica = replicas.sample
|
107
126
|
return Config.new(host: replica["ip"], port: Integer(replica["port"]), **@client_config)
|
108
127
|
end
|
128
|
+
rescue ConnectionError
|
129
|
+
raise ConnectionError, "No sentinels available"
|
130
|
+
else
|
109
131
|
raise ConnectionError, "Couldn't locate a replica for role: #{@name}"
|
110
132
|
end
|
111
133
|
|
data/lib/redis_client/version.rb
CHANGED
data/lib/redis_client.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
|
-
|
5
3
|
require "redis_client/version"
|
6
4
|
require "redis_client/command_builder"
|
7
5
|
require "redis_client/config"
|
@@ -78,17 +76,18 @@ class RedisClient
|
|
78
76
|
|
79
77
|
Error = Class.new(StandardError)
|
80
78
|
|
79
|
+
ProtocolError = Class.new(Error)
|
81
80
|
UnsupportedServer = Class.new(Error)
|
82
81
|
|
83
82
|
ConnectionError = Class.new(Error)
|
83
|
+
CannotConnectError = Class.new(ConnectionError)
|
84
84
|
|
85
85
|
FailoverError = Class.new(ConnectionError)
|
86
86
|
|
87
87
|
TimeoutError = Class.new(ConnectionError)
|
88
88
|
ReadTimeoutError = Class.new(TimeoutError)
|
89
89
|
WriteTimeoutError = Class.new(TimeoutError)
|
90
|
-
|
91
|
-
CheckoutTimeoutError = Class.new(ConnectTimeoutError)
|
90
|
+
CheckoutTimeoutError = Class.new(TimeoutError)
|
92
91
|
|
93
92
|
class CommandError < Error
|
94
93
|
attr_reader :command
|
@@ -120,11 +119,11 @@ class RedisClient
|
|
120
119
|
|
121
120
|
class << self
|
122
121
|
def config(**kwargs)
|
123
|
-
Config.new(**kwargs)
|
122
|
+
Config.new(client_implementation: self, **kwargs)
|
124
123
|
end
|
125
124
|
|
126
125
|
def sentinel(**kwargs)
|
127
|
-
SentinelConfig.new(**kwargs)
|
126
|
+
SentinelConfig.new(client_implementation: self, **kwargs)
|
128
127
|
end
|
129
128
|
|
130
129
|
def new(arg = nil, **kwargs)
|
@@ -184,7 +183,22 @@ class RedisClient
|
|
184
183
|
end
|
185
184
|
|
186
185
|
def call(*command, **kwargs)
|
187
|
-
command = @command_builder.generate
|
186
|
+
command = @command_builder.generate(command, kwargs)
|
187
|
+
result = ensure_connected do |connection|
|
188
|
+
Middlewares.call(command, config) do
|
189
|
+
connection.call(command, nil)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if block_given?
|
194
|
+
yield result
|
195
|
+
else
|
196
|
+
result
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def call_v(command)
|
201
|
+
command = @command_builder.generate(command)
|
188
202
|
result = ensure_connected do |connection|
|
189
203
|
Middlewares.call(command, config) do
|
190
204
|
connection.call(command, nil)
|
@@ -199,7 +213,22 @@ class RedisClient
|
|
199
213
|
end
|
200
214
|
|
201
215
|
def call_once(*command, **kwargs)
|
202
|
-
command = @command_builder.generate
|
216
|
+
command = @command_builder.generate(command, kwargs)
|
217
|
+
result = ensure_connected(retryable: false) do |connection|
|
218
|
+
Middlewares.call(command, config) do
|
219
|
+
connection.call(command, nil)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
if block_given?
|
224
|
+
yield result
|
225
|
+
else
|
226
|
+
result
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def call_once_v(command)
|
231
|
+
command = @command_builder.generate(command)
|
203
232
|
result = ensure_connected(retryable: false) do |connection|
|
204
233
|
Middlewares.call(command, config) do
|
205
234
|
connection.call(command, nil)
|
@@ -214,14 +243,39 @@ class RedisClient
|
|
214
243
|
end
|
215
244
|
|
216
245
|
def blocking_call(timeout, *command, **kwargs)
|
217
|
-
command = @command_builder.generate
|
246
|
+
command = @command_builder.generate(command, kwargs)
|
247
|
+
error = nil
|
218
248
|
result = ensure_connected do |connection|
|
219
249
|
Middlewares.call(command, config) do
|
220
250
|
connection.call(command, timeout)
|
221
251
|
end
|
252
|
+
rescue ReadTimeoutError => error
|
253
|
+
break
|
222
254
|
end
|
223
255
|
|
224
|
-
if
|
256
|
+
if error
|
257
|
+
raise error
|
258
|
+
elsif block_given?
|
259
|
+
yield result
|
260
|
+
else
|
261
|
+
result
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def blocking_call_v(timeout, command)
|
266
|
+
command = @command_builder.generate(command)
|
267
|
+
error = nil
|
268
|
+
result = ensure_connected do |connection|
|
269
|
+
Middlewares.call(command, config) do
|
270
|
+
connection.call(command, timeout)
|
271
|
+
end
|
272
|
+
rescue ReadTimeoutError => error
|
273
|
+
break
|
274
|
+
end
|
275
|
+
|
276
|
+
if error
|
277
|
+
raise error
|
278
|
+
elsif block_given?
|
225
279
|
yield result
|
226
280
|
else
|
227
281
|
result
|
@@ -233,7 +287,7 @@ class RedisClient
|
|
233
287
|
return to_enum(__callee__, *args, **kwargs)
|
234
288
|
end
|
235
289
|
|
236
|
-
args = @command_builder.generate
|
290
|
+
args = @command_builder.generate(["SCAN", 0] + args, kwargs)
|
237
291
|
scan_list(1, args, &block)
|
238
292
|
end
|
239
293
|
|
@@ -242,7 +296,7 @@ class RedisClient
|
|
242
296
|
return to_enum(__callee__, key, *args, **kwargs)
|
243
297
|
end
|
244
298
|
|
245
|
-
args = @command_builder.generate
|
299
|
+
args = @command_builder.generate(["SSCAN", key, 0] + args, kwargs)
|
246
300
|
scan_list(2, args, &block)
|
247
301
|
end
|
248
302
|
|
@@ -251,7 +305,7 @@ class RedisClient
|
|
251
305
|
return to_enum(__callee__, key, *args, **kwargs)
|
252
306
|
end
|
253
307
|
|
254
|
-
args = @command_builder.generate
|
308
|
+
args = @command_builder.generate(["HSCAN", key, 0] + args, kwargs)
|
255
309
|
scan_pairs(2, args, &block)
|
256
310
|
end
|
257
311
|
|
@@ -260,7 +314,7 @@ class RedisClient
|
|
260
314
|
return to_enum(__callee__, key, *args, **kwargs)
|
261
315
|
end
|
262
316
|
|
263
|
-
args = @command_builder.generate
|
317
|
+
args = @command_builder.generate(["ZSCAN", key, 0] + args, kwargs)
|
264
318
|
scan_pairs(2, args, &block)
|
265
319
|
end
|
266
320
|
|
@@ -343,7 +397,12 @@ class RedisClient
|
|
343
397
|
end
|
344
398
|
|
345
399
|
def call(*command, **kwargs)
|
346
|
-
raw_connection.write(@command_builder.generate
|
400
|
+
raw_connection.write(@command_builder.generate(command, kwargs))
|
401
|
+
nil
|
402
|
+
end
|
403
|
+
|
404
|
+
def call_v(command)
|
405
|
+
raw_connection.write(@command_builder.generate(command))
|
347
406
|
nil
|
348
407
|
end
|
349
408
|
|
@@ -378,14 +437,29 @@ class RedisClient
|
|
378
437
|
end
|
379
438
|
|
380
439
|
def call(*command, **kwargs, &block)
|
381
|
-
command = @command_builder.generate
|
440
|
+
command = @command_builder.generate(command, kwargs)
|
441
|
+
(@blocks ||= [])[@commands.size] = block if block_given?
|
442
|
+
@commands << command
|
443
|
+
nil
|
444
|
+
end
|
445
|
+
|
446
|
+
def call_v(command, &block)
|
447
|
+
command = @command_builder.generate(command)
|
382
448
|
(@blocks ||= [])[@commands.size] = block if block_given?
|
383
449
|
@commands << command
|
384
450
|
nil
|
385
451
|
end
|
386
452
|
|
387
|
-
def call_once(*command, **kwargs)
|
388
|
-
command = @command_builder.generate
|
453
|
+
def call_once(*command, **kwargs, &block)
|
454
|
+
command = @command_builder.generate(command, kwargs)
|
455
|
+
@retryable = false
|
456
|
+
(@blocks ||= [])[@commands.size] = block if block_given?
|
457
|
+
@commands << command
|
458
|
+
nil
|
459
|
+
end
|
460
|
+
|
461
|
+
def call_once_v(command, &block)
|
462
|
+
command = @command_builder.generate(command)
|
389
463
|
@retryable = false
|
390
464
|
(@blocks ||= [])[@commands.size] = block if block_given?
|
391
465
|
@commands << command
|
@@ -417,18 +491,14 @@ class RedisClient
|
|
417
491
|
end
|
418
492
|
|
419
493
|
def _coerce!(results)
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
raise result
|
425
|
-
end
|
494
|
+
results&.each_with_index do |result, index|
|
495
|
+
if result.is_a?(CommandError)
|
496
|
+
result._set_command(@commands[index + 1])
|
497
|
+
raise result
|
426
498
|
end
|
427
499
|
|
428
|
-
@blocks
|
429
|
-
|
430
|
-
results[index - 1] = block.call(results[index - 1])
|
431
|
-
end
|
500
|
+
if @blocks && block = @blocks[index + 1]
|
501
|
+
results[index] = block.call(result)
|
432
502
|
end
|
433
503
|
end
|
434
504
|
|
@@ -442,8 +512,17 @@ class RedisClient
|
|
442
512
|
@timeouts = nil
|
443
513
|
end
|
444
514
|
|
445
|
-
def blocking_call(timeout, *command, **kwargs)
|
446
|
-
command = @command_builder.generate
|
515
|
+
def blocking_call(timeout, *command, **kwargs, &block)
|
516
|
+
command = @command_builder.generate(command, kwargs)
|
517
|
+
@timeouts ||= []
|
518
|
+
@timeouts[@commands.size] = timeout
|
519
|
+
(@blocks ||= [])[@commands.size] = block if block_given?
|
520
|
+
@commands << command
|
521
|
+
nil
|
522
|
+
end
|
523
|
+
|
524
|
+
def blocking_call_v(timeout, command, &block)
|
525
|
+
command = @command_builder.generate(command)
|
447
526
|
@timeouts ||= []
|
448
527
|
@timeouts[@commands.size] = timeout
|
449
528
|
(@blocks ||= [])[@commands.size] = block if block_given?
|
@@ -521,7 +600,7 @@ class RedisClient
|
|
521
600
|
else
|
522
601
|
connection
|
523
602
|
end
|
524
|
-
rescue ConnectionError => error
|
603
|
+
rescue ConnectionError, ProtocolError => error
|
525
604
|
connection&.close
|
526
605
|
close
|
527
606
|
|
@@ -538,6 +617,10 @@ class RedisClient
|
|
538
617
|
begin
|
539
618
|
@disable_reconnection = true
|
540
619
|
yield connection
|
620
|
+
rescue ConnectionError, ProtocolError
|
621
|
+
connection&.close
|
622
|
+
close
|
623
|
+
raise
|
541
624
|
ensure
|
542
625
|
@disable_reconnection = previous_disable_reconnection
|
543
626
|
end
|
@@ -568,10 +651,16 @@ class RedisClient
|
|
568
651
|
role, = connection.call_pipelined(prelude, nil).last
|
569
652
|
config.check_role!(role)
|
570
653
|
else
|
571
|
-
|
654
|
+
unless prelude.empty?
|
655
|
+
connection.call_pipelined(prelude, nil)
|
656
|
+
end
|
572
657
|
end
|
573
658
|
|
574
659
|
connection
|
660
|
+
rescue FailoverError
|
661
|
+
raise
|
662
|
+
rescue ConnectionError => error
|
663
|
+
raise CannotConnectError, error.message, error.backtrace
|
575
664
|
rescue CommandError => error
|
576
665
|
if error.message.include?("ERR unknown command `HELLO`")
|
577
666
|
raise UnsupportedServer,
|
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.6.2
|
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-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|