redis-cluster-client 0.0.6 → 0.0.9

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: fde84481c2ca9680670f252a002391a34ae793148a21a8e02086d199412a53ab
4
- data.tar.gz: 5af188432f9ae5e76c13d0dd174c25cde4b98d1de49efeb97e2a809bd111a9a6
3
+ metadata.gz: 032431ff16773725b9cb68482bc5df78affdf23e66b6bbd91b6ddbabdd9da921
4
+ data.tar.gz: dc789f59f6509e35ab23df03a70867b5e8414ee3bb327462fbcd5d63be4c6744
5
5
  SHA512:
6
- metadata.gz: f26dc7bb447ee70742efc90344758ad3058cd0d1506ad8576637b7e9ad296a806d7e15e3b824cead0fb2313140dea00f6f579a15803399c16257ac347c45085f
7
- data.tar.gz: 06f43e223a53d9ada0803f7292bc1ca58505fb3c341fd7643eb6cf0eff73bebe4ecd2022b0a1b59af81dda879a9d8a9b078107181ff45037773382dada321597
6
+ metadata.gz: 6013ff65d8dc06b776b7b201244d75eaf62993368f5285d823472f78bec2c81639734f23c32793bc1b8d1981905e5794e35e4e353696d70f1d66930434e6104f
7
+ data.tar.gz: 0e1dc5f17a9706c2fc64bdd03e74ee457f9b9aea81740cdeb5459bd9bbc769b6353047b64ef008b6d34b950fbc7cb8cf57e66c9deb41d33edbacaba78ca2a12e
@@ -68,12 +68,14 @@ class RedisClient
68
68
  @details.fetch(name).fetch(key)
69
69
  end
70
70
 
71
- def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity
71
+ def determine_first_key_position(command) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
72
72
  case command&.flatten&.first.to_s.downcase
73
- when 'eval', 'evalsha', 'migrate', 'zinterstore', 'zunionstore' then 3
73
+ when 'eval', 'evalsha', 'zinterstore', 'zunionstore' then 3
74
74
  when 'object' then 2
75
75
  when 'memory'
76
76
  command[1].to_s.casecmp('usage').zero? ? 2 : 0
77
+ when 'migrate'
78
+ command[3] == '""' ? determine_optional_key_position(command, 'keys') : 3
77
79
  when 'xread', 'xreadgroup'
78
80
  determine_optional_key_position(command, 'streams')
79
81
  else
@@ -29,7 +29,7 @@ class RedisClient
29
29
  end
30
30
 
31
31
  # Raised when error occurs on any node of cluster.
32
- class CommandErrorCollection < ::RedisClient::Error
32
+ class ErrorCollection < ::RedisClient::Error
33
33
  attr_reader :errors
34
34
 
35
35
  def initialize(errors)
@@ -51,5 +51,15 @@ class RedisClient
51
51
  super("Cluster client doesn't know which node the #{command} command should be sent to.")
52
52
  end
53
53
  end
54
+
55
+ class NodeMightBeDown < ::RedisClient::Error
56
+ def initialize(_ = '')
57
+ super(
58
+ 'The client is trying to fetch the latest cluster state '\
59
+ 'because a subset of nodes might be down. '\
60
+ 'It might continue to raise errors for a while.'
61
+ )
62
+ end
63
+ end
54
64
  end
55
65
  end
@@ -43,6 +43,8 @@ class RedisClient
43
43
  module_function
44
44
 
45
45
  def convert(key)
46
+ return nil if key.nil?
47
+
46
48
  crc = 0
47
49
  key.each_byte do |b|
48
50
  crc = ((crc << 8) & 0xffff) ^ XMODEM_CRC16_LOOKUP[((crc >> 8) ^ b) & 0xff]
@@ -12,6 +12,7 @@ class RedisClient
12
12
  SLOT_SIZE = 16_384
13
13
  MIN_SLOT = 0
14
14
  MAX_SLOT = SLOT_SIZE - 1
15
+ MAX_STARTUP_SAMPLE = 37
15
16
  IGNORE_GENERIC_CONFIG_KEYS = %i[url host port path].freeze
16
17
 
17
18
  ReloadNeeded = Class.new(::RedisClient::Error)
@@ -32,19 +33,33 @@ class RedisClient
32
33
  end
33
34
 
34
35
  class << self
35
- def load_info(options, **kwargs)
36
- startup_nodes = ::RedisClient::Cluster::Node.new(options, **kwargs)
37
-
38
- errors = startup_nodes.map do |n|
39
- reply = n.call('CLUSTER', 'NODES')
40
- return parse_node_info(reply)
41
- rescue ::RedisClient::ConnectionError, ::RedisClient::CommandError => e
42
- e
36
+ def load_info(options, **kwargs) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
37
+ startup_size = options.size > MAX_STARTUP_SAMPLE ? MAX_STARTUP_SAMPLE : options.size
38
+ node_info_list = Array.new(startup_size)
39
+ errors = Array.new(startup_size)
40
+ startup_options = options.to_a.sample(MAX_STARTUP_SAMPLE).to_h
41
+ startup_nodes = ::RedisClient::Cluster::Node.new(startup_options, **kwargs)
42
+ threads = startup_nodes.each_with_index.map do |raw_client, idx|
43
+ Thread.new(raw_client, idx) do |cli, i|
44
+ Thread.pass
45
+ reply = cli.call('CLUSTER', 'NODES')
46
+ node_info_list[i] = parse_node_info(reply)
47
+ rescue StandardError => e
48
+ errors[i] = e
49
+ ensure
50
+ cli&.close
51
+ end
52
+ end
53
+ threads.each(&:join)
54
+ raise ::RedisClient::Cluster::InitialSetupError, errors if node_info_list.all?(&:nil?)
55
+
56
+ grouped = node_info_list.compact.group_by do |rows|
57
+ rows.sort_by { |row| row[:id] }
58
+ .map { |r| "#{r[:id]}#{r[:node_key]}#{r[:role]}#{r[:primary_id]}#{r[:config_epoch]}" }
59
+ .join
43
60
  end
44
61
 
45
- raise ::RedisClient::Cluster::InitialSetupError, errors
46
- ensure
47
- startup_nodes&.each(&:close)
62
+ grouped.max_by { |_, v| v.size }[1].first
48
63
  end
49
64
 
50
65
  private
@@ -109,32 +124,58 @@ class RedisClient
109
124
  end
110
125
 
111
126
  def find_by(node_key)
127
+ raise ReloadNeeded if node_key.nil? || !@clients.key?(node_key)
128
+
112
129
  @clients.fetch(node_key)
113
- rescue KeyError
114
- raise ReloadNeeded
115
130
  end
116
131
 
117
- def call_all(method, *command, **kwargs, &block)
118
- try_map { |_, client| client.send(method, *command, **kwargs, &block) }.values
132
+ def call_all(method, *args, **kwargs, &block)
133
+ results, errors = try_map do |_, client|
134
+ client.send(method, *args, **kwargs, &block)
135
+ end
136
+
137
+ return results.values if errors.empty?
138
+
139
+ raise ::RedisClient::Cluster::ErrorCollection, errors
119
140
  end
120
141
 
121
- def call_primary(method, *command, **kwargs, &block)
122
- try_map do |node_key, client|
142
+ def call_primaries(method, *args, **kwargs, &block)
143
+ results, errors = try_map do |node_key, client|
123
144
  next if replica?(node_key)
124
145
 
125
- client.send(method, *command, **kwargs, &block)
126
- end.values
146
+ client.send(method, *args, **kwargs, &block)
147
+ end
148
+
149
+ return results.values if errors.empty?
150
+
151
+ raise ::RedisClient::Cluster::ErrorCollection, errors
127
152
  end
128
153
 
129
- def call_replica(method, *command, **kwargs, &block)
130
- return call_primary(method, *command, **kwargs, &block) if replica_disabled?
154
+ def call_replicas(method, *args, **kwargs, &block)
155
+ return call_primaries(method, *args, **kwargs, &block) if replica_disabled?
131
156
 
132
157
  replica_node_keys = @replications.values.map(&:sample)
133
- try_map do |node_key, client|
158
+ results, errors = try_map do |node_key, client|
134
159
  next if primary?(node_key) || !replica_node_keys.include?(node_key)
135
160
 
136
- client.send(method, *command, **kwargs, &block)
137
- end.values
161
+ client.send(method, *args, **kwargs, &block)
162
+ end
163
+
164
+ return results.values if errors.empty?
165
+
166
+ raise ::RedisClient::Cluster::ErrorCollection, errors
167
+ end
168
+
169
+ def send_ping(method, *args, **kwargs, &block)
170
+ results, errors = try_map do |_, client|
171
+ client.send(method, *args, **kwargs, &block)
172
+ end
173
+
174
+ return results.values if errors.empty?
175
+
176
+ raise ReloadNeeded if errors.values.any?(::RedisClient::ConnectionError)
177
+
178
+ raise ::RedisClient::Cluster::ErrorCollection, errors
138
179
  end
139
180
 
140
181
  def scale_reading_clients
@@ -144,14 +185,9 @@ class RedisClient
144
185
  end
145
186
  end
146
187
 
147
- def slot_exists?(slot)
148
- slot = Integer(slot)
149
- return false if slot < MIN_SLOT || slot > MAX_SLOT
150
-
151
- !@slots[slot].nil?
152
- end
153
-
154
188
  def find_node_key_of_primary(slot)
189
+ return if slot.nil?
190
+
155
191
  slot = Integer(slot)
156
192
  return if slot < MIN_SLOT || slot > MAX_SLOT
157
193
 
@@ -159,6 +195,8 @@ class RedisClient
159
195
  end
160
196
 
161
197
  def find_node_key_of_replica(slot)
198
+ return if slot.nil?
199
+
162
200
  slot = Integer(slot)
163
201
  return if slot < MIN_SLOT || slot > MAX_SLOT
164
202
 
@@ -228,22 +266,20 @@ class RedisClient
228
266
  end
229
267
 
230
268
  def try_map # rubocop:disable Metrics/MethodLength
231
- errors = {}
232
269
  results = {}
270
+ errors = {}
233
271
  threads = @clients.map do |k, v|
234
272
  Thread.new(k, v) do |node_key, client|
235
273
  Thread.pass
236
274
  reply = yield(node_key, client)
237
275
  results[node_key] = reply unless reply.nil?
238
- rescue ::RedisClient::CommandError => e
276
+ rescue StandardError => e
239
277
  errors[node_key] = e
240
278
  end
241
279
  end
242
280
 
243
281
  threads.each(&:join)
244
- return results if errors.empty?
245
-
246
- raise ::RedisClient::Cluster::CommandErrorCollection, errors
282
+ [results, errors]
247
283
  end
248
284
  end
249
285
  end
@@ -40,9 +40,10 @@ class RedisClient
40
40
  @size.zero?
41
41
  end
42
42
 
43
- # TODO: https://github.com/redis-rb/redis-cluster-client/issues/37
44
- def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
43
+ # TODO: https://github.com/redis-rb/redis-cluster-client/issues/37 handle redirections
44
+ def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
45
45
  all_replies = Array.new(@size)
46
+ errors = {}
46
47
  threads = @grouped.map do |k, v|
47
48
  Thread.new(@client, k, v) do |client, node_key, rows|
48
49
  Thread.pass
@@ -60,11 +61,15 @@ class RedisClient
60
61
  raise ReplySizeError, "commands: #{rows.size}, replies: #{replies.size}" if rows.size != replies.size
61
62
 
62
63
  rows.each_with_index { |row, idx| all_replies[row.first] = replies[idx] }
64
+ rescue StandardError => e
65
+ errors[node_key] = e
63
66
  end
64
67
  end
65
68
 
66
69
  threads.each(&:join)
67
- all_replies
70
+ return all_replies if errors.empty?
71
+
72
+ raise ::RedisClient::Cluster::ErrorCollection, errors
68
73
  end
69
74
  end
70
75
 
@@ -122,8 +127,7 @@ class RedisClient
122
127
  end
123
128
 
124
129
  def blocking_call(timeout, *command, **kwargs)
125
- node = assign_node(*command)
126
- try_send(node, :blocking_call, timeout, *command, **kwargs)
130
+ send_command(:blocking_call, timeout, *command, **kwargs)
127
131
  end
128
132
 
129
133
  def scan(*args, **kwargs, &block)
@@ -165,8 +169,10 @@ class RedisClient
165
169
  end
166
170
 
167
171
  def close
168
- @node.each(&:close)
172
+ @node.call_all(:close)
169
173
  nil
174
+ rescue StandardError
175
+ # ignore
170
176
  end
171
177
 
172
178
  private
@@ -179,102 +185,124 @@ class RedisClient
179
185
  node_info: node_info, pool: pool, with_replica: config.use_replica?, **kwargs)
180
186
  end
181
187
 
182
- def send_command(method, *command, **kwargs, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
188
+ def send_command(method, *args, **kwargs, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
189
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
190
+
183
191
  cmd = command.first.to_s.downcase
184
192
  case cmd
185
- when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save', 'ping'
186
- @node.call_all(method, *command, **kwargs, &block).first
193
+ when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
194
+ @node.call_all(method, *args, **kwargs, &block).first
187
195
  when 'flushall', 'flushdb'
188
- @node.call_primary(method, *command, **kwargs, &block).first
189
- when 'wait' then send_wait_command(method, *command, **kwargs, &block)
190
- when 'keys' then @node.call_replica(method, *command, **kwargs, &block).flatten.sort
191
- when 'dbsize' then @node.call_replica(method, *command, **kwargs, &block).sum
196
+ @node.call_primaries(method, *args, **kwargs, &block).first
197
+ when 'ping' then @node.send_ping(method, *args, **kwargs, &block).first
198
+ when 'wait' then send_wait_command(method, *args, **kwargs, &block)
199
+ when 'keys' then @node.call_replicas(method, *args, **kwargs, &block).flatten.sort
200
+ when 'dbsize' then @node.call_replicas(method, *args, **kwargs, &block).sum
192
201
  when 'scan' then _scan(*command, **kwargs)
193
- when 'lastsave' then @node.call_all(method, *command, **kwargs, &block).sort
194
- when 'role' then @node.call_all(method, *command, **kwargs, &block)
195
- when 'config' then send_config_command(method, *command, **kwargs, &block)
196
- when 'client' then send_client_command(method, *command, **kwargs, &block)
197
- when 'cluster' then send_cluster_command(method, *command, **kwargs, &block)
202
+ when 'lastsave' then @node.call_all(method, *args, **kwargs, &block).sort
203
+ when 'role' then @node.call_all(method, *args, **kwargs, &block)
204
+ when 'config' then send_config_command(method, *args, **kwargs, &block)
205
+ when 'client' then send_client_command(method, *args, **kwargs, &block)
206
+ when 'cluster' then send_cluster_command(method, *args, **kwargs, &block)
198
207
  when 'readonly', 'readwrite', 'shutdown'
199
208
  raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, cmd
200
- when 'memory' then send_memory_command(method, *command, **kwargs, &block)
201
- when 'script' then send_script_command(method, *command, **kwargs, &block)
202
- when 'pubsub' then send_pubsub_command(method, *command, **kwargs, &block)
209
+ when 'memory' then send_memory_command(method, *args, **kwargs, &block)
210
+ when 'script' then send_script_command(method, *args, **kwargs, &block)
211
+ when 'pubsub' then send_pubsub_command(method, *args, **kwargs, &block)
203
212
  when 'discard', 'exec', 'multi', 'unwatch'
204
213
  raise ::RedisClient::Cluster::AmbiguousNodeError, cmd
205
214
  else
206
215
  node = assign_node(*command)
207
- try_send(node, method, *command, **kwargs, &block)
216
+ try_send(node, method, *args, **kwargs, &block)
208
217
  end
209
- rescue RedisClient::Cluster::CommandErrorCollection => e
210
- update_cluster_info! if e.errors.values.map(&:class).any?(::RedisClient::ConnectionError)
211
- raise
218
+ rescue RedisClient::Cluster::Node::ReloadNeeded
219
+ update_cluster_info!
220
+ raise ::RedisClient::Cluster::NodeMightBeDown
212
221
  end
213
222
 
214
- def send_wait_command(method, *command, retry_count: 3, **kwargs, &block)
215
- @node.call_primary(method, *command, **kwargs, &block).sum
216
- rescue RedisClient::Cluster::CommandErrorCollection => e
217
- raise if retry_count <= 0 || e.errors.values.map(&:message).grep(/ERR WAIT cannot be used with replica instances/).empty?
223
+ def send_wait_command(method, *args, retry_count: 3, **kwargs, &block)
224
+ @node.call_primaries(method, *args, **kwargs, &block).sum
225
+ rescue RedisClient::Cluster::ErrorCollection => e
226
+ raise if retry_count <= 0
227
+ raise if e.errors.values.none? do |err|
228
+ err.message.include?('WAIT cannot be used with replica instances')
229
+ end
218
230
 
219
231
  update_cluster_info!
220
232
  retry_count -= 1
221
233
  retry
222
234
  end
223
235
 
224
- def send_config_command(method, *command, **kwargs, &block)
236
+ def send_config_command(method, *args, **kwargs, &block)
237
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
238
+
225
239
  case command[1].to_s.downcase
226
240
  when 'resetstat', 'rewrite', 'set'
227
- @node.call_all(method, *command, **kwargs, &block).first
228
- else assign_node(*command).send(method, *command, **kwargs, &block)
241
+ @node.call_all(method, *args, **kwargs, &block).first
242
+ else assign_node(*command).send(method, *args, **kwargs, &block)
229
243
  end
230
244
  end
231
245
 
232
- def send_memory_command(method, *command, **kwargs, &block)
246
+ def send_memory_command(method, *args, **kwargs, &block)
247
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
248
+
233
249
  case command[1].to_s.downcase
234
- when 'stats' then @node.call_all(method, *command, **kwargs, &block)
235
- when 'purge' then @node.call_all(method, *command, **kwargs, &block).first
236
- else assign_node(*command).send(method, *command, **kwargs, &block)
250
+ when 'stats' then @node.call_all(method, *args, **kwargs, &block)
251
+ when 'purge' then @node.call_all(method, *args, **kwargs, &block).first
252
+ else assign_node(*command).send(method, *args, **kwargs, &block)
237
253
  end
238
254
  end
239
255
 
240
- def send_client_command(method, *command, **kwargs, &block)
256
+ def send_client_command(method, *args, **kwargs, &block)
257
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
258
+
241
259
  case command[1].to_s.downcase
242
- when 'list' then @node.call_all(method, *command, **kwargs, &block).flatten
260
+ when 'list' then @node.call_all(method, *args, **kwargs, &block).flatten
243
261
  when 'pause', 'reply', 'setname'
244
- @node.call_all(method, *command, **kwargs, &block).first
245
- else assign_node(*command).send(method, *command, **kwargs, &block)
262
+ @node.call_all(method, *args, **kwargs, &block).first
263
+ else assign_node(*command).send(method, *args, **kwargs, &block)
246
264
  end
247
265
  end
248
266
 
249
- def send_cluster_command(method, *command, **kwargs, &block)
267
+ def send_cluster_command(method, *args, **kwargs, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
268
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
250
269
  subcommand = command[1].to_s.downcase
270
+
251
271
  case subcommand
252
272
  when 'addslots', 'delslots', 'failover', 'forget', 'meet', 'replicate',
253
273
  'reset', 'set-config-epoch', 'setslot'
254
274
  raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, ['cluster', subcommand]
255
- when 'saveconfig' then @node.call_all(method, *command, **kwargs, &block).first
256
- else assign_node(*command).send(method, *command, **kwargs, &block)
275
+ when 'saveconfig' then @node.call_all(method, *args, **kwargs, &block).first
276
+ when 'getkeysinslot'
277
+ raise ArgumentError, command.join(' ') if command.size != 4
278
+
279
+ find_node(@node.find_node_key_of_replica(command[2])).send(method, *args, **kwargs, &block)
280
+ else assign_node(*command).send(method, *args, **kwargs, &block)
257
281
  end
258
282
  end
259
283
 
260
- def send_script_command(method, *command, **kwargs, &block)
284
+ def send_script_command(method, *args, **kwargs, &block)
285
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
286
+
261
287
  case command[1].to_s.downcase
262
288
  when 'debug', 'kill'
263
- @node.call_all(method, *command, **kwargs, &block).first
289
+ @node.call_all(method, *args, **kwargs, &block).first
264
290
  when 'flush', 'load'
265
- @node.call_primary(method, *command, **kwargs, &block).first
266
- else assign_node(*command).send(method, *command, **kwargs, &block)
291
+ @node.call_primaries(method, *args, **kwargs, &block).first
292
+ else assign_node(*command).send(method, *args, **kwargs, &block)
267
293
  end
268
294
  end
269
295
 
270
- def send_pubsub_command(method, *command, **kwargs, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
296
+ def send_pubsub_command(method, *args, **kwargs, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
297
+ command = method == :blocking_call && args.size > 1 ? args[1..] : args
298
+
271
299
  case command[1].to_s.downcase
272
- when 'channels' then @node.call_all(method, *command, **kwargs, &block).flatten.uniq.sort
300
+ when 'channels' then @node.call_all(method, *args, **kwargs, &block).flatten.uniq.sort
273
301
  when 'numsub'
274
- @node.call_all(method, *command, **kwargs, &block).reject(&:empty?).map { |e| Hash[*e] }
302
+ @node.call_all(method, *args, **kwargs, &block).reject(&:empty?).map { |e| Hash[*e] }
275
303
  .reduce({}) { |a, e| a.merge(e) { |_, v1, v2| v1 + v2 } }
276
- when 'numpat' then @node.call_all(method, *command, **kwargs, &block).sum
277
- else assign_node(*command).send(method, *command, **kwargs, &block)
304
+ when 'numpat' then @node.call_all(method, *args, **kwargs, &block).sum
305
+ else assign_node(*command).send(method, *args, **kwargs, &block)
278
306
  end
279
307
  end
280
308
 
@@ -344,44 +372,30 @@ class RedisClient
344
372
  find_node(node_key)
345
373
  end
346
374
 
347
- def find_node_key(*command, primary_only: false) # rubocop:disable Metrics/MethodLength
375
+ def find_node_key(*command, primary_only: false)
348
376
  key = @command.extract_first_key(command)
349
- if key.empty?
350
- return @node.primary_node_keys.sample if @command.should_send_to_primary?(command) || primary_only
351
-
352
- return @node.replica_node_keys.sample
353
- end
354
-
355
- slot = ::RedisClient::Cluster::KeySlotConverter.convert(key)
356
- return unless @node.slot_exists?(slot)
377
+ slot = key.empty? ? nil : ::RedisClient::Cluster::KeySlotConverter.convert(key)
357
378
 
358
379
  if @command.should_send_to_primary?(command) || primary_only
359
- @node.find_node_key_of_primary(slot)
380
+ @node.find_node_key_of_primary(slot) || @node.primary_node_keys.sample
360
381
  else
361
- @node.find_node_key_of_replica(slot)
382
+ @node.find_node_key_of_replica(slot) || @node.replica_node_keys.sample
362
383
  end
363
384
  end
364
385
 
365
386
  def find_node(node_key, retry_count: 3)
366
- return @node.sample if node_key.nil?
367
-
368
387
  @node.find_by(node_key)
369
388
  rescue ::RedisClient::Cluster::Node::ReloadNeeded
370
- raise(::RedisClient::ConnectionError, 'unstable cluster state') if retry_count <= 0
389
+ raise ::RedieClient::Cluster::NodeMightBeDown if retry_count <= 0
371
390
 
372
- update_cluster_info!(node_key)
391
+ update_cluster_info!
373
392
  retry_count -= 1
374
393
  retry
375
394
  end
376
395
 
377
- def update_cluster_info!(node_key = nil)
396
+ def update_cluster_info!
378
397
  @mutex.synchronize do
379
- unless node_key.nil?
380
- host, port = ::RedisClient::Cluster::NodeKey.split(node_key)
381
- @config.add_node(host, port)
382
- end
383
-
384
- @node.each(&:close)
398
+ close
385
399
  @node = fetch_cluster_info!(@config, pool: @pool, **@client_kwargs)
386
400
  end
387
401
  end
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.0.6
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taishi Kasuga
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-19 00:00:00.000000000 Z
11
+ date: 2022-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client