redis-cluster-client 0.3.15 → 0.4.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 780e5f1653b6633dbd4bb1bdc4f4da174d70176a5287bf6156ad5784f0612cf1
|
4
|
+
data.tar.gz: ca1681357111afdc82bdf32a18985963dba85f89fd49961ac62c56075daa0cc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4111e4b1305d955d3eb56df912debd0cfbbd388bae1d841cf1b9274a21d2e121fb511f1630d85f6c503d53ebf514503303b94402d3416517886b93f615584a22
|
7
|
+
data.tar.gz: 1f6e2be52bcd834482d17bebfeead2b8d1346c954d03b61251dd973ab19f27275e53571d73ba6425dceedc34dc07cd5e6dbb98fa46de00281b6d00eeb1c87f08
|
@@ -43,7 +43,7 @@ class RedisClient
|
|
43
43
|
clients.each_slice(::RedisClient::Cluster::Node::MAX_THREADS).each_with_object({}) do |chuncked_clients, acc|
|
44
44
|
threads = chuncked_clients.map do |k, v|
|
45
45
|
Thread.new(k, v) do |node_key, client|
|
46
|
-
Thread.current
|
46
|
+
Thread.current[:node_key] = node_key
|
47
47
|
|
48
48
|
min = DUMMY_LATENCY_NSEC
|
49
49
|
MEASURE_ATTEMPT_COUNT.times do
|
@@ -53,15 +53,15 @@ class RedisClient
|
|
53
53
|
min = duration if duration < min
|
54
54
|
end
|
55
55
|
|
56
|
-
Thread.current
|
56
|
+
Thread.current[:latency] = min
|
57
57
|
rescue StandardError
|
58
|
-
Thread.current
|
58
|
+
Thread.current[:latency] = DUMMY_LATENCY_NSEC
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
62
|
threads.each do |t|
|
63
63
|
t.join
|
64
|
-
acc[t
|
64
|
+
acc[t[:node_key]] = t[:latency]
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -18,7 +18,6 @@ class RedisClient
|
|
18
18
|
MAX_STARTUP_SAMPLE = 37
|
19
19
|
MAX_THREADS = Integer(ENV.fetch('REDIS_CLIENT_MAX_THREADS', 5))
|
20
20
|
IGNORE_GENERIC_CONFIG_KEYS = %i[url host port path].freeze
|
21
|
-
SLOT_OPTIMIZATION_STRING = '0' * SLOT_SIZE
|
22
21
|
|
23
22
|
ReloadNeeded = Class.new(::RedisClient::Error)
|
24
23
|
|
@@ -37,27 +36,36 @@ class RedisClient
|
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
|
-
|
39
|
+
class CharArray
|
40
|
+
BASE = ''
|
41
|
+
PADDING = '0'
|
42
|
+
|
43
|
+
def initialize(size, elements)
|
44
|
+
@elements = elements
|
45
|
+
@string = String.new(BASE, encoding: Encoding::BINARY, capacity: size)
|
46
|
+
size.times { @string << PADDING }
|
47
|
+
end
|
48
|
+
|
41
49
|
def [](index)
|
42
50
|
raise IndexError if index < 0
|
43
|
-
return if index >= string.bytesize
|
51
|
+
return if index >= @string.bytesize
|
44
52
|
|
45
|
-
elements[string.getbyte(index)]
|
53
|
+
@elements[@string.getbyte(index)]
|
46
54
|
end
|
47
55
|
|
48
56
|
def []=(index, element)
|
49
57
|
raise IndexError if index < 0
|
50
|
-
return if index >= string.bytesize
|
58
|
+
return if index >= @string.bytesize
|
51
59
|
|
52
|
-
pos = elements.find_index(element) # O(N)
|
60
|
+
pos = @elements.find_index(element) # O(N)
|
53
61
|
if pos.nil?
|
54
|
-
raise(RangeError, 'full of elements') if elements.size >= 256
|
62
|
+
raise(RangeError, 'full of elements') if @elements.size >= 256
|
55
63
|
|
56
|
-
pos = elements.size
|
57
|
-
elements << element
|
64
|
+
pos = @elements.size
|
65
|
+
@elements << element
|
58
66
|
end
|
59
67
|
|
60
|
-
string.setbyte(index, pos)
|
68
|
+
@string.setbyte(index, pos)
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
@@ -85,11 +93,11 @@ class RedisClient
|
|
85
93
|
startup_nodes.each_slice(MAX_THREADS).with_index do |chuncked_startup_nodes, chuncked_idx|
|
86
94
|
threads = chuncked_startup_nodes.each_with_index.map do |raw_client, idx|
|
87
95
|
Thread.new(raw_client, (MAX_THREADS * chuncked_idx) + idx) do |cli, i|
|
88
|
-
Thread.current
|
96
|
+
Thread.current[:index] = i
|
89
97
|
reply = cli.call('CLUSTER', 'NODES')
|
90
|
-
Thread.current
|
98
|
+
Thread.current[:info] = parse_cluster_node_reply(reply)
|
91
99
|
rescue StandardError => e
|
92
|
-
Thread.current
|
100
|
+
Thread.current[:error] = e
|
93
101
|
ensure
|
94
102
|
cli&.close
|
95
103
|
end
|
@@ -97,12 +105,12 @@ class RedisClient
|
|
97
105
|
|
98
106
|
threads.each do |t|
|
99
107
|
t.join
|
100
|
-
if t.
|
108
|
+
if t.key?(:info)
|
101
109
|
node_info_list ||= Array.new(startup_size)
|
102
|
-
node_info_list[t
|
103
|
-
elsif t.
|
110
|
+
node_info_list[t[:index]] = t[:info]
|
111
|
+
elsif t.key?(:error)
|
104
112
|
errors ||= Array.new(startup_size)
|
105
|
-
errors[t
|
113
|
+
errors[t[:index]] = t[:error]
|
106
114
|
end
|
107
115
|
end
|
108
116
|
end
|
@@ -268,10 +276,8 @@ class RedisClient
|
|
268
276
|
def make_array_for_slot_node_mappings(node_info_list)
|
269
277
|
return Array.new(SLOT_SIZE) if node_info_list.count(&:primary?) > 256
|
270
278
|
|
271
|
-
|
272
|
-
|
273
|
-
elements: node_info_list.select(&:primary?).map(&:node_key)
|
274
|
-
)
|
279
|
+
primary_node_keys = node_info_list.select(&:primary?).map(&:node_key)
|
280
|
+
::RedisClient::Cluster::Node::CharArray.new(SLOT_SIZE, primary_node_keys)
|
275
281
|
end
|
276
282
|
|
277
283
|
def build_replication_mappings(node_info_list) # rubocop:disable Metrics/AbcSize
|
@@ -303,22 +309,22 @@ class RedisClient
|
|
303
309
|
clients.each_slice(MAX_THREADS) do |chuncked_clients|
|
304
310
|
threads = chuncked_clients.map do |k, v|
|
305
311
|
Thread.new(k, v) do |node_key, client|
|
306
|
-
Thread.current
|
312
|
+
Thread.current[:node_key] = node_key
|
307
313
|
reply = yield(node_key, client)
|
308
|
-
Thread.current
|
314
|
+
Thread.current[:result] = reply
|
309
315
|
rescue StandardError => e
|
310
|
-
Thread.current
|
316
|
+
Thread.current[:error] = e
|
311
317
|
end
|
312
318
|
end
|
313
319
|
|
314
320
|
threads.each do |t|
|
315
321
|
t.join
|
316
|
-
if t.
|
322
|
+
if t.key?(:result)
|
317
323
|
results ||= {}
|
318
|
-
results[t
|
319
|
-
elsif t.
|
324
|
+
results[t[:node_key]] = t[:result]
|
325
|
+
elsif t.key?(:error)
|
320
326
|
errors ||= {}
|
321
|
-
errors[t
|
327
|
+
errors[t[:node_key]] = t[:error]
|
322
328
|
end
|
323
329
|
end
|
324
330
|
end
|
@@ -150,34 +150,34 @@ class RedisClient
|
|
150
150
|
@pipelines&.each_slice(MAX_THREADS) do |chuncked_pipelines|
|
151
151
|
threads = chuncked_pipelines.map do |node_key, pipeline|
|
152
152
|
Thread.new(node_key, pipeline) do |nk, pl|
|
153
|
-
Thread.current
|
153
|
+
Thread.current[:node_key] = nk
|
154
154
|
replies = do_pipelining(@router.find_node(nk), pl)
|
155
155
|
raise ReplySizeError, "commands: #{pl._size}, replies: #{replies.size}" if pl._size != replies.size
|
156
156
|
|
157
|
-
Thread.current
|
157
|
+
Thread.current[:replies] = replies
|
158
158
|
rescue ::RedisClient::Cluster::Pipeline::RedirectionNeeded => e
|
159
|
-
Thread.current
|
159
|
+
Thread.current[:redirection_needed] = e
|
160
160
|
rescue StandardError => e
|
161
|
-
Thread.current
|
161
|
+
Thread.current[:error] = e
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
165
165
|
threads.each(&:join)
|
166
166
|
threads.each do |t|
|
167
|
-
if t.
|
167
|
+
if t.key?(:replies)
|
168
168
|
all_replies ||= Array.new(@size)
|
169
|
-
@pipelines[t
|
169
|
+
@pipelines[t[:node_key]]
|
170
170
|
.outer_indices
|
171
|
-
.each_with_index { |outer, inner| all_replies[outer] = t
|
172
|
-
elsif t.
|
171
|
+
.each_with_index { |outer, inner| all_replies[outer] = t[:replies][inner] }
|
172
|
+
elsif t.key?(:redirection_needed)
|
173
173
|
all_replies ||= Array.new(@size)
|
174
|
-
pipeline = @pipelines[t
|
175
|
-
err = t
|
174
|
+
pipeline = @pipelines[t[:node_key]]
|
175
|
+
err = t[:redirection_needed]
|
176
176
|
err.indices.each { |i| err.replies[i] = handle_redirection(err.replies[i], pipeline, i) }
|
177
177
|
pipeline.outer_indices.each_with_index { |outer, inner| all_replies[outer] = err.replies[inner] }
|
178
|
-
elsif t.
|
178
|
+
elsif t.key?(:error)
|
179
179
|
errors ||= {}
|
180
|
-
errors[t
|
180
|
+
errors[t[:node_key]] = t[:error]
|
181
181
|
end
|
182
182
|
end
|
183
183
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'redis_client'
|
4
|
+
require 'redis_client/circuit_breaker'
|
4
5
|
require 'redis_client/cluster/command'
|
5
6
|
require 'redis_client/cluster/errors'
|
6
7
|
require 'redis_client/cluster/key_slot_converter'
|
@@ -54,13 +55,18 @@ class RedisClient
|
|
54
55
|
node = assign_node(command)
|
55
56
|
try_send(node, method, command, args, &block)
|
56
57
|
end
|
58
|
+
rescue ::RedisClient::CircuitBreaker::OpenCircuitError
|
59
|
+
raise
|
57
60
|
rescue ::RedisClient::Cluster::Node::ReloadNeeded
|
58
61
|
update_cluster_info!
|
59
62
|
raise ::RedisClient::Cluster::NodeMightBeDown
|
60
63
|
rescue ::RedisClient::Cluster::ErrorCollection => e
|
64
|
+
raise if e.errors.any?(::RedisClient::CircuitBreaker::OpenCircuitError)
|
65
|
+
|
61
66
|
update_cluster_info! if e.errors.values.any? do |err|
|
62
67
|
err.message.start_with?('CLUSTERDOWN Hash slot not served')
|
63
68
|
end
|
69
|
+
|
64
70
|
raise
|
65
71
|
end
|
66
72
|
|
@@ -72,6 +78,8 @@ class RedisClient
|
|
72
78
|
else
|
73
79
|
node.public_send(method, *args, command, &block)
|
74
80
|
end
|
81
|
+
rescue ::RedisClient::CircuitBreaker::OpenCircuitError
|
82
|
+
raise
|
75
83
|
rescue ::RedisClient::CommandError => e
|
76
84
|
raise if retry_count <= 0
|
77
85
|
|
@@ -102,6 +110,8 @@ class RedisClient
|
|
102
110
|
|
103
111
|
def try_delegate(node, method, *args, retry_count: 3, **kwargs, &block) # rubocop:disable Metrics/AbcSize
|
104
112
|
node.public_send(method, *args, **kwargs, &block)
|
113
|
+
rescue ::RedisClient::CircuitBreaker::OpenCircuitError
|
114
|
+
raise
|
105
115
|
rescue ::RedisClient::CommandError => e
|
106
116
|
raise if retry_count <= 0
|
107
117
|
|
@@ -197,9 +207,10 @@ class RedisClient
|
|
197
207
|
|
198
208
|
private
|
199
209
|
|
200
|
-
def send_wait_command(method, command, args, retry_count: 3, &block)
|
210
|
+
def send_wait_command(method, command, args, retry_count: 3, &block) # rubocop:disable Metrics/AbcSize
|
201
211
|
@node.call_primaries(method, command, args, &block).select { |r| r.is_a?(Integer) }.sum
|
202
212
|
rescue ::RedisClient::Cluster::ErrorCollection => e
|
213
|
+
raise if e.errors.any?(::RedisClient::CircuitBreaker::OpenCircuitError)
|
203
214
|
raise if retry_count <= 0
|
204
215
|
raise if e.errors.values.none? do |err|
|
205
216
|
err.message.include?('WAIT cannot be used with replica instances')
|
@@ -98,7 +98,7 @@ class RedisClient
|
|
98
98
|
|
99
99
|
def build_node_configs(addrs)
|
100
100
|
configs = Array[addrs].flatten.filter_map { |addr| parse_node_addr(addr) }
|
101
|
-
raise InvalidClientConfigError, '`nodes` option is empty' if configs.
|
101
|
+
raise InvalidClientConfigError, '`nodes` option is empty' if configs.empty?
|
102
102
|
|
103
103
|
configs
|
104
104
|
end
|
@@ -150,7 +150,7 @@ class RedisClient
|
|
150
150
|
end
|
151
151
|
|
152
152
|
def merge_generic_config(client_config, node_configs)
|
153
|
-
return client_config if node_configs.
|
153
|
+
return client_config if node_configs.empty?
|
154
154
|
|
155
155
|
cfg = node_configs.first
|
156
156
|
MERGE_CONFIG_KEYS.each { |k| client_config[k] = cfg[k] if cfg.key?(k) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-cluster-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taishi Kasuga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.12'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.12'
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- proxy0721@gmail.com
|