redis-cluster-client 0.11.6 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e31ae2691d5dac09f55bffb25f1a5af9f0f300d9b71246f998d7a18ad6d6d97
4
- data.tar.gz: 7331c0ea5c04d95bb9325ad235edbede9fa872dacdcc1df2745214241600f7fa
3
+ metadata.gz: 2465b865cd79c78cca3a1e7e3950989cce94f6675b0497763e03e261d3fa9c6f
4
+ data.tar.gz: df607279a58171aca75835b767f3bf5965256db0fcb7b540bfcb3a8f302eb638
5
5
  SHA512:
6
- metadata.gz: f8752f06007254fd8c73716f3a93853062e8bb61d9381cdf66e56f705a4f7c391e0f2685ee2b75d97d2bd25aac815ae17997e0982b0774c78324b04637af1574
7
- data.tar.gz: f995c63ae5e11ff31a0ce4feaef8c421620244c192d32ae3522a71ca62956b362962c15a87daa8c76c50018368c2851d0c99c83b6a061fa1ef7024da3df4e6fd
6
+ metadata.gz: bfb9031660b642bb14768dc8edc66fb15073be9ca23ddc061d279a351c497a83ff8a3aad21903e2d0a37aa6824da35761188ba4dc1fe8ae0182b54584edaa5e5
7
+ data.tar.gz: 9fab63d0595bfb7dac85a07c255a41573ab8d44598605919fd4182e99cf3da585bf931abe63da9e2f470815c6ef0d34ab24a5b7f2de346ba29870fb894c556ee
@@ -25,7 +25,7 @@ class RedisClient
25
25
  )
26
26
 
27
27
  class << self
28
- def load(nodes, slow_command_timeout: -1)
28
+ def load(nodes, slow_command_timeout: -1) # rubocop:disable Metrics/AbcSize
29
29
  cmd = errors = nil
30
30
 
31
31
  nodes&.each do |node|
@@ -43,7 +43,7 @@ class RedisClient
43
43
 
44
44
  return cmd unless cmd.nil?
45
45
 
46
- raise ::RedisClient::Cluster::InitialSetupError, errors
46
+ raise ::RedisClient::Cluster::InitialSetupError.from_errors(errors)
47
47
  end
48
48
 
49
49
  private
@@ -4,51 +4,60 @@ require 'redis_client'
4
4
 
5
5
  class RedisClient
6
6
  class Cluster
7
+ class Error < ::RedisClient::Error
8
+ def with_config(config)
9
+ @config = config
10
+ self
11
+ end
12
+ end
13
+
7
14
  ERR_ARG_NORMALIZATION = ->(arg) { Array[arg].flatten.reject { |e| e.nil? || (e.respond_to?(:empty?) && e.empty?) } }
8
15
 
9
16
  private_constant :ERR_ARG_NORMALIZATION
10
17
 
11
- class InitialSetupError < ::RedisClient::Error
12
- def initialize(errors)
18
+ class InitialSetupError < Error
19
+ def self.from_errors(errors)
13
20
  msg = ERR_ARG_NORMALIZATION.call(errors).map(&:message).uniq.join(',')
14
- super("Redis client could not fetch cluster information: #{msg}")
21
+ new("Redis client could not fetch cluster information: #{msg}")
15
22
  end
16
23
  end
17
24
 
18
- class OrchestrationCommandNotSupported < ::RedisClient::Error
19
- def initialize(command)
25
+ class OrchestrationCommandNotSupported < Error
26
+ def self.from_command(command)
20
27
  str = ERR_ARG_NORMALIZATION.call(command).map(&:to_s).join(' ').upcase
21
28
  msg = "#{str} command should be used with care " \
22
29
  'only by applications orchestrating Redis Cluster, like redis-cli, ' \
23
30
  'and the command if used out of the right context can leave the cluster ' \
24
31
  'in a wrong state or cause data loss.'
25
- super(msg)
32
+ new(msg)
26
33
  end
27
34
  end
28
35
 
29
- class ErrorCollection < ::RedisClient::Error
36
+ class ErrorCollection < Error
30
37
  attr_reader :errors
31
38
 
32
- def initialize(errors)
33
- @errors = {}
39
+ def self.with_errors(errors)
34
40
  if !errors.is_a?(Hash) || errors.empty?
35
- super(errors.to_s)
36
- return
41
+ new(errors.to_s).with_errors({})
42
+ else
43
+ messages = errors.map { |node_key, error| "#{node_key}: (#{error.class}) #{error.message}" }
44
+ new(messages.join(', ')).with_errors(errors)
37
45
  end
46
+ end
38
47
 
39
- @errors = errors
40
- messages = @errors.map { |node_key, error| "#{node_key}: (#{error.class}) #{error.message}" }
41
- super(messages.join(', '))
48
+ def with_errors(errors)
49
+ @errors = errors if @errors.nil?
50
+ self
42
51
  end
43
52
  end
44
53
 
45
- class AmbiguousNodeError < ::RedisClient::Error
46
- def initialize(command)
47
- super("Cluster client doesn't know which node the #{command} command should be sent to.")
54
+ class AmbiguousNodeError < Error
55
+ def self.from_command(command)
56
+ new("Cluster client doesn't know which node the #{command} command should be sent to.")
48
57
  end
49
58
  end
50
59
 
51
- class NodeMightBeDown < ::RedisClient::Error
60
+ class NodeMightBeDown < Error
52
61
  def initialize(_ = '')
53
62
  super(
54
63
  'The client is trying to fetch the latest cluster state ' \
@@ -28,7 +28,7 @@ class RedisClient
28
28
  private_constant :USE_CHAR_ARRAY_SLOT, :SLOT_SIZE, :MIN_SLOT, :MAX_SLOT,
29
29
  :DEAD_FLAGS, :ROLE_FLAGS, :EMPTY_ARRAY, :EMPTY_HASH
30
30
 
31
- ReloadNeeded = Class.new(::RedisClient::Error)
31
+ ReloadNeeded = Class.new(::RedisClient::Cluster::Error)
32
32
 
33
33
  Info = Struct.new(
34
34
  'RedisClusterNode',
@@ -148,7 +148,7 @@ class RedisClient
148
148
 
149
149
  raise ReloadNeeded if errors.values.any?(::RedisClient::ConnectionError)
150
150
 
151
- raise ::RedisClient::Cluster::ErrorCollection, errors
151
+ raise ::RedisClient::Cluster::ErrorCollection.with_errors(errors)
152
152
  end
153
153
 
154
154
  def clients_for_scanning(seed: nil)
@@ -267,7 +267,7 @@ class RedisClient
267
267
  result_values, errors = call_multiple_nodes(clients, method, command, args, &block)
268
268
  return result_values if errors.nil? || errors.empty?
269
269
 
270
- raise ::RedisClient::Cluster::ErrorCollection, errors
270
+ raise ::RedisClient::Cluster::ErrorCollection.with_errors(errors)
271
271
  end
272
272
 
273
273
  def try_map(clients, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
@@ -334,7 +334,7 @@ class RedisClient
334
334
 
335
335
  work_group.close
336
336
 
337
- raise ::RedisClient::Cluster::InitialSetupError, errors if node_info_list.nil?
337
+ raise ::RedisClient::Cluster::InitialSetupError.from_errors(errors) if node_info_list.nil?
338
338
 
339
339
  grouped = node_info_list.compact.group_by do |info_list|
340
340
  info_list.sort_by!(&:id)
@@ -108,13 +108,13 @@ class RedisClient
108
108
  end
109
109
  end
110
110
 
111
- ReplySizeError = Class.new(::RedisClient::Error)
111
+ ReplySizeError = Class.new(::RedisClient::Cluster::Error)
112
112
 
113
- class StaleClusterState < ::RedisClient::Error
113
+ class StaleClusterState < ::RedisClient::Cluster::Error
114
114
  attr_accessor :replies, :first_exception
115
115
  end
116
116
 
117
- class RedirectionNeeded < ::RedisClient::Error
117
+ class RedirectionNeeded < ::RedisClient::Cluster::Error
118
118
  attr_accessor :replies, :indices, :first_exception
119
119
  end
120
120
 
@@ -204,7 +204,7 @@ class RedisClient
204
204
 
205
205
  work_group.close
206
206
  @router.renew_cluster_state if cluster_state_errors
207
- raise ::RedisClient::Cluster::ErrorCollection, errors unless errors.nil?
207
+ raise ::RedisClient::Cluster::ErrorCollection.with_errors(errors).with_config(@router.config) unless errors.nil?
208
208
 
209
209
  required_redirections&.each do |node_key, v|
210
210
  raise v.first_exception if v.first_exception
@@ -21,10 +21,10 @@ class RedisClient
21
21
 
22
22
  private_constant :ZERO_CURSOR_FOR_SCAN, :TSF
23
23
 
24
+ attr_reader :config
25
+
24
26
  def initialize(config, concurrent_worker, pool: nil, **kwargs)
25
- @config = config.dup
26
- @original_config = config.dup if config.connect_with_original_config
27
- @connect_with_original_config = config.connect_with_original_config
27
+ @config = config
28
28
  @concurrent_worker = concurrent_worker
29
29
  @pool = pool
30
30
  @client_kwargs = kwargs
@@ -32,6 +32,9 @@ class RedisClient
32
32
  @node.reload!
33
33
  @command = ::RedisClient::Cluster::Command.load(@node.replica_clients.shuffle, slow_command_timeout: config.slow_command_timeout)
34
34
  @command_builder = @config.command_builder
35
+ rescue ::RedisClient::Cluster::InitialSetupError => e
36
+ e.with_config(config)
37
+ raise
35
38
  end
36
39
 
37
40
  def send_command(method, command, *args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -58,9 +61,9 @@ class RedisClient
58
61
  when 'flushall', 'flushdb'
59
62
  @node.call_primaries(method, command, args).first.then(&TSF.call(block))
60
63
  when 'readonly', 'readwrite', 'shutdown'
61
- raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, cmd
64
+ raise ::RedisClient::Cluster::OrchestrationCommandNotSupported.from_command(cmd).with_config(@config)
62
65
  when 'discard', 'exec', 'multi', 'unwatch'
63
- raise ::RedisClient::Cluster::AmbiguousNodeError, cmd
66
+ raise ::RedisClient::Cluster::AmbiguousNodeError.from_command(cmd).with_config(@config)
64
67
  else
65
68
  node = assign_node(command)
66
69
  try_send(node, method, command, args, &block)
@@ -69,7 +72,7 @@ class RedisClient
69
72
  raise
70
73
  rescue ::RedisClient::Cluster::Node::ReloadNeeded
71
74
  renew_cluster_state
72
- raise ::RedisClient::Cluster::NodeMightBeDown
75
+ raise ::RedisClient::Cluster::NodeMightBeDown.new.with_config(@config)
73
76
  rescue ::RedisClient::ConnectionError
74
77
  renew_cluster_state
75
78
  raise
@@ -77,6 +80,7 @@ class RedisClient
77
80
  renew_cluster_state if e.message.start_with?('CLUSTERDOWN')
78
81
  raise
79
82
  rescue ::RedisClient::Cluster::ErrorCollection => e
83
+ e.with_config(@config)
80
84
  raise if e.errors.any?(::RedisClient::CircuitBreaker::OpenCircuitError)
81
85
 
82
86
  renew_cluster_state if e.errors.values.any? do |err|
@@ -189,7 +193,7 @@ class RedisClient
189
193
  node_key = primary ? @node.find_node_key_of_primary(slot) : @node.find_node_key_of_replica(slot)
190
194
  if node_key.nil?
191
195
  renew_cluster_state
192
- raise ::RedisClient::Cluster::NodeMightBeDown
196
+ raise ::RedisClient::Cluster::NodeMightBeDown.new.with_config(@config)
193
197
  end
194
198
  node_key
195
199
  else
@@ -303,7 +307,7 @@ class RedisClient
303
307
  case subcommand = ::RedisClient::Cluster::NormalizedCmdName.instance.get_by_subcommand(command)
304
308
  when 'addslots', 'delslots', 'failover', 'forget', 'meet', 'replicate',
305
309
  'reset', 'set-config-epoch', 'setslot'
306
- raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, ['cluster', subcommand]
310
+ raise ::RedisClient::Cluster::OrchestrationCommandNotSupported.from_command(['cluster', subcommand]).with_config(@config)
307
311
  when 'saveconfig' then @node.call_all(method, command, args).first.then(&TSF.call(block))
308
312
  when 'getkeysinslot'
309
313
  raise ArgumentError, command.join(' ') if command.size != 4
@@ -347,7 +351,10 @@ class RedisClient
347
351
  end
348
352
 
349
353
  def send_watch_command(command)
350
- raise ::RedisClient::Cluster::Transaction::ConsistencyError, 'A block required. And you need to use the block argument as a client for the transaction.' unless block_given?
354
+ unless block_given?
355
+ msg = 'A block required. And you need to use the block argument as a client for the transaction.'
356
+ raise ::RedisClient::Cluster::Transaction::ConsistencyError.new(msg).with_config(@config)
357
+ end
351
358
 
352
359
  ::RedisClient::Cluster::OptimisticLocking.new(self).watch(command[1..]) do |c, slot, asking|
353
360
  transaction = ::RedisClient::Cluster::Transaction.new(
@@ -401,7 +408,7 @@ class RedisClient
401
408
  def handle_node_reload_error(retry_count: 1)
402
409
  yield
403
410
  rescue ::RedisClient::Cluster::Node::ReloadNeeded
404
- raise ::RedisClient::Cluster::NodeMightBeDown if retry_count <= 0
411
+ raise ::RedisClient::Cluster::NodeMightBeDown.new.with_config(@config) if retry_count <= 0
405
412
 
406
413
  retry_count -= 1
407
414
  renew_cluster_state
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'redis_client'
4
+ require 'redis_client/cluster/errors'
4
5
  require 'redis_client/cluster/pipeline'
5
6
 
6
7
  class RedisClient
7
8
  class Cluster
8
9
  class Transaction
9
- ConsistencyError = Class.new(::RedisClient::Error)
10
+ ConsistencyError = Class.new(::RedisClient::Cluster::Error)
10
11
 
11
12
  MAX_REDIRECTION = 2
12
13
  EMPTY_ARRAY = [].freeze
@@ -67,7 +68,7 @@ class RedisClient
67
68
  @pending_commands.each(&:call)
68
69
 
69
70
  return EMPTY_ARRAY if @pipeline._empty?
70
- raise ConsistencyError, "couldn't determine the node: #{@pipeline._commands}" if @node.nil?
71
+ raise ConsistencyError.new("couldn't determine the node: #{@pipeline._commands}").with_config(@router.config) if @node.nil?
71
72
 
72
73
  commit
73
74
  end
@@ -163,7 +164,7 @@ class RedisClient
163
164
 
164
165
  def handle_command_error!(err, redirect:) # rubocop:disable Metrics/AbcSize
165
166
  if err.message.start_with?('CROSSSLOT')
166
- raise ConsistencyError, "#{err.message}: #{err.command}"
167
+ raise ConsistencyError.new("#{err.message}: #{err.command}").with_config(@router.config)
167
168
  elsif err.message.start_with?('MOVED')
168
169
  node = @router.assign_redirection_node(err.message)
169
170
  send_transaction(node, redirect: redirect - 1)
@@ -183,7 +184,7 @@ class RedisClient
183
184
  return if slots.size == 1 && @watching_slot.nil?
184
185
  return if slots.size == 1 && @watching_slot == slots.first
185
186
 
186
- raise(ConsistencyError, "the transaction should be executed to a slot in a node: #{commands}")
187
+ raise ConsistencyError.new("the transaction should be executed to a slot in a node: #{commands}").with_config(@router.config)
187
188
  end
188
189
 
189
190
  def try_asking(node)
@@ -3,6 +3,7 @@
3
3
  require 'uri'
4
4
  require 'redis_client'
5
5
  require 'redis_client/cluster'
6
+ require 'redis_client/cluster/errors'
6
7
  require 'redis_client/cluster/node_key'
7
8
  require 'redis_client/command_builder'
8
9
 
@@ -27,10 +28,10 @@ class RedisClient
27
28
  :VALID_SCHEMES, :VALID_NODES_KEYS, :MERGE_CONFIG_KEYS, :IGNORE_GENERIC_CONFIG_KEYS,
28
29
  :MAX_WORKERS, :SLOW_COMMAND_TIMEOUT, :MAX_STARTUP_SAMPLE
29
30
 
30
- InvalidClientConfigError = Class.new(::RedisClient::Error)
31
+ InvalidClientConfigError = Class.new(::RedisClient::Cluster::Error)
31
32
 
32
33
  attr_reader :command_builder, :client_config, :replica_affinity, :slow_command_timeout,
33
- :connect_with_original_config, :startup_nodes, :max_startup_sample
34
+ :connect_with_original_config, :startup_nodes, :max_startup_sample, :id
34
35
 
35
36
  def initialize( # rubocop:disable Metrics/ParameterLists
36
37
  nodes: DEFAULT_NODES,
@@ -59,6 +60,7 @@ class RedisClient
59
60
  @client_implementation = client_implementation
60
61
  @slow_command_timeout = slow_command_timeout
61
62
  @max_startup_sample = max_startup_sample
63
+ @id = client_config[:id]
62
64
  end
63
65
 
64
66
  def inspect
@@ -92,6 +94,18 @@ class RedisClient
92
94
  augment_client_config(config)
93
95
  end
94
96
 
97
+ def resolved?
98
+ true
99
+ end
100
+
101
+ def sentinel?
102
+ false
103
+ end
104
+
105
+ def server_url
106
+ nil
107
+ end
108
+
95
109
  private
96
110
 
97
111
  def merge_concurrency_option(option)
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.11.6
4
+ version: 0.12.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: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2024-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
77
  - !ruby/object:Gem::Version
78
78
  version: '0'
79
79
  requirements: []
80
- rubygems_version: 3.5.16
80
+ rubygems_version: 3.5.22
81
81
  signing_key:
82
82
  specification_version: 4
83
83
  summary: A Redis cluster client for Ruby