redis-cluster-client 0.4.2 → 0.4.3

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: 5bd4bae00bd7df3abda8f68a53f08746abae7c818f22466e8ec3e52c3e978b5b
4
- data.tar.gz: c78d5b8600d131655d8fcf63744928a9f62718d78aaa3ddb5fd73908b1716314
3
+ metadata.gz: 4e29792dd4eb3b7609baa8943b25a385c87dd36767ba679e9c9209be765a670b
4
+ data.tar.gz: 367d7cb722ef026b76c7f200237c1c64a0dced84026c78a43feb55a72eb7accb
5
5
  SHA512:
6
- metadata.gz: c78d564a0398b6adfc0217568fd22ff7227215db616f8052142ebf45999a70930ce0f4b76363d6f0ac1030bffa9673bc25566815d6eac8bacf84247fd9e162f2
7
- data.tar.gz: c992c9a5faf59fc2929351e99d6e112cd0fd464397fad0d4952a5997abebdf0b2fdfd8d691c4a96aea0856639423c99519d538bc422ce66943d34292a242224d
6
+ metadata.gz: c3b7eb12f99b928072eeb00f4465afc5be3a3cb07aeabfc821369151f94ebbf12029409317c21b57cb628710e786e1e423b84f543b7430c23d89f71e9fe9339b
7
+ data.tar.gz: c317f99c5bb51be184f4aab415017260237e3614e535565649bb90d79a2b47c7b9edfb07c83b3a96ead85849c7bd97639ce6d60eb1f957df351908ae098f6795
@@ -10,6 +10,7 @@ class RedisClient
10
10
  EMPTY_STRING = ''
11
11
  LEFT_BRACKET = '{'
12
12
  RIGHT_BRACKET = '}'
13
+ EMPTY_HASH = {}.freeze
13
14
 
14
15
  Detail = Struct.new(
15
16
  'RedisCommand',
@@ -21,15 +22,15 @@ class RedisClient
21
22
 
22
23
  class << self
23
24
  def load(nodes)
24
- errors = []
25
- cmd = nil
26
- nodes&.each do |node|
27
- break unless cmd.nil?
25
+ cmd = errors = nil
28
26
 
27
+ nodes&.each do |node|
29
28
  reply = node.call('COMMAND')
30
29
  commands = parse_command_reply(reply)
31
30
  cmd = ::RedisClient::Cluster::Command.new(commands)
31
+ break
32
32
  rescue ::RedisClient::Error => e
33
+ errors ||= []
33
34
  errors << e
34
35
  end
35
36
 
@@ -41,21 +42,20 @@ class RedisClient
41
42
  private
42
43
 
43
44
  def parse_command_reply(rows)
44
- rows&.reject { |row| row[0].nil? }.to_h do |row|
45
- [
46
- row[0].downcase,
47
- ::RedisClient::Cluster::Command::Detail.new(
48
- first_key_position: row[3],
49
- write?: row[2].include?('write'),
50
- readonly?: row[2].include?('readonly')
51
- )
52
- ]
53
- end
45
+ rows&.each_with_object({}) do |row, acc|
46
+ next if row[0].nil?
47
+
48
+ acc[row[0].downcase] = ::RedisClient::Cluster::Command::Detail.new(
49
+ first_key_position: row[3],
50
+ write?: row[2].include?('write'),
51
+ readonly?: row[2].include?('readonly')
52
+ )
53
+ end.freeze || EMPTY_HASH
54
54
  end
55
55
  end
56
56
 
57
57
  def initialize(commands)
58
- @commands = commands || {}
58
+ @commands = commands || EMPTY_HASH
59
59
  end
60
60
 
61
61
  def extract_first_key(command)
@@ -18,6 +18,9 @@ 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
+ DEAD_FLAGS = %w[fail? fail handshake noaddr noflags].freeze
22
+ ROLE_FLAGS = %w[master slave].freeze
23
+ EMPTY_ARRAY = [].freeze
21
24
 
22
25
  ReloadNeeded = Class.new(::RedisClient::Error)
23
26
 
@@ -118,13 +121,13 @@ class RedisClient
118
121
  raise ::RedisClient::Cluster::InitialSetupError, errors if node_info_list.nil?
119
122
 
120
123
  grouped = node_info_list.compact.group_by do |info_list|
121
- info_list
122
- .sort_by(&:id)
123
- .map { |i| "#{i.id}#{i.node_key}#{i.role}#{i.primary_id}#{i.config_epoch}" }
124
- .join
124
+ info_list.sort_by!(&:id)
125
+ info_list.each_with_object(String.new(capacity: 128 * info_list.size)) do |e, a|
126
+ a << e.id << e.node_key << e.role << e.primary_id << e.config_epoch
127
+ end
125
128
  end
126
129
 
127
- grouped.max_by { |_, v| v.size }[1].first
130
+ grouped.max_by { |_, v| v.size }[1].first.freeze
128
131
  end
129
132
 
130
133
  private
@@ -132,27 +135,47 @@ class RedisClient
132
135
  # @see https://redis.io/commands/cluster-nodes/
133
136
  # @see https://github.com/redis/redis/blob/78960ad57b8a5e6af743d789ed8fd767e37d42b8/src/cluster.c#L4660-L4683
134
137
  def parse_cluster_node_reply(reply) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
135
- rows = reply.split("\n").map(&:split)
136
- rows.each { |arr| arr[2] = arr[2].split(',') }
137
- rows.select! { |arr| arr[7] == 'connected' && (arr[2] & %w[fail? fail handshake noaddr noflags]).empty? }
138
- rows.each do |arr|
139
- arr[1] = arr[1].split('@').first
140
- arr[2] = (arr[2] & %w[master slave]).first
141
- if arr[8].nil?
142
- arr[8] = []
143
- next
144
- end
145
- arr[8] = arr[8..].filter_map { |str| str.start_with?('[') ? nil : str.split('-').map { |s| Integer(s) } }
146
- .map { |a| a.size == 1 ? a << a.first : a }.map(&:sort)
147
- end
138
+ reply.each_line("\n", chomp: true).filter_map do |line|
139
+ fields = line.split
140
+ flags = fields[2].split(',')
141
+ next unless fields[7] == 'connected' && (flags & DEAD_FLAGS).empty?
142
+
143
+ slots = if fields[8].nil?
144
+ EMPTY_ARRAY
145
+ else
146
+ fields[8..].reject { |str| str.start_with?('[') }
147
+ .map { |str| str.split('-').map { |s| Integer(s) } }
148
+ .map { |a| a.size == 1 ? a << a.first : a }
149
+ .map(&:sort)
150
+ end
148
151
 
149
- rows.map do |arr|
150
152
  ::RedisClient::Cluster::Node::Info.new(
151
- id: arr[0], node_key: arr[1], role: arr[2], primary_id: arr[3], ping_sent: arr[4],
152
- pong_recv: arr[5], config_epoch: arr[6], link_state: arr[7], slots: arr[8]
153
+ id: fields[0],
154
+ node_key: parse_node_key(fields[1]),
155
+ role: (flags & ROLE_FLAGS).first,
156
+ primary_id: fields[3],
157
+ ping_sent: fields[4],
158
+ pong_recv: fields[5],
159
+ config_epoch: fields[6],
160
+ link_state: fields[7],
161
+ slots: slots
153
162
  )
154
163
  end
155
164
  end
165
+
166
+ # As redirection node_key is dependent on `cluster-preferred-endpoint-type` config,
167
+ # node_key should use hostname if present in CLUSTER NODES output.
168
+ #
169
+ # See https://redis.io/commands/cluster-nodes/ for details on the output format.
170
+ # node_address matches fhe format: <ip:port@cport[,hostname[,auxiliary_field=value]*]>
171
+ def parse_node_key(node_address)
172
+ ip_chunk, hostname, _auxiliaries = node_address.split(',')
173
+ ip_port_string = ip_chunk.split('@').first
174
+ return ip_port_string if hostname.nil? || hostname.empty?
175
+
176
+ port = ip_port_string.split(':')[1]
177
+ "#{hostname}:#{port}"
178
+ end
156
179
  end
157
180
 
158
181
  def initialize(
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.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taishi Kasuga
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-03 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.12'
27
- description:
27
+ description:
28
28
  email:
29
29
  - proxy0721@gmail.com
30
30
  executables: []
@@ -54,7 +54,7 @@ licenses:
54
54
  metadata:
55
55
  rubygems_mfa_required: 'true'
56
56
  allowed_push_host: https://rubygems.org
57
- post_install_message:
57
+ post_install_message:
58
58
  rdoc_options: []
59
59
  require_paths:
60
60
  - lib
@@ -69,8 +69,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  requirements: []
72
- rubygems_version: 3.3.23
73
- signing_key:
72
+ rubygems_version: 3.4.6
73
+ signing_key:
74
74
  specification_version: 4
75
75
  summary: A Redis cluster client for Ruby
76
76
  test_files: []