redis-cluster-client 0.0.11 → 0.2.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 +4 -4
- data/lib/redis-cluster-client.rb +3 -0
- data/lib/redis_client/cluster/command.rb +4 -0
- data/lib/redis_client/cluster/node.rb +9 -9
- data/lib/redis_client/cluster/pipeline.rb +38 -18
- data/lib/redis_client/cluster/pub_sub.rb +13 -4
- data/lib/redis_client/cluster/router.rb +96 -63
- data/lib/redis_client/cluster.rb +55 -16
- data/lib/redis_client/cluster_config.rb +12 -3
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5160c83d23cb638fc76cf079377981d6778560ba0eb476da03f58d6f4eded9af
|
4
|
+
data.tar.gz: dd0baec0d24de14e2cba10c4ea3f45af7f1bef2db30f609c9551ed2d13c0bf4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cf5c16776bb7ff4c53ffa66e3de3371c1130fed7a4916982e7fba9859ba9ae7505af0bc5e8e02b58f22d116ab74692a4572d835f05672457bac4ddd469e3162
|
7
|
+
data.tar.gz: f08215c00f2b12b00247604917a7f7abc228ddd0e4305c67af38f8e2087a8b3785a22bfbd09ac32f75789719a624be49663f5048f6187318477069e4ef9627a1
|
@@ -128,9 +128,9 @@ class RedisClient
|
|
128
128
|
@clients.fetch(node_key)
|
129
129
|
end
|
130
130
|
|
131
|
-
def call_all(method,
|
131
|
+
def call_all(method, command, args, &block)
|
132
132
|
results, errors = try_map do |_, client|
|
133
|
-
client.send(method, *args,
|
133
|
+
client.send(method, *args, command, &block)
|
134
134
|
end
|
135
135
|
|
136
136
|
return results.values if errors.empty?
|
@@ -138,11 +138,11 @@ class RedisClient
|
|
138
138
|
raise ::RedisClient::Cluster::ErrorCollection, errors
|
139
139
|
end
|
140
140
|
|
141
|
-
def call_primaries(method,
|
141
|
+
def call_primaries(method, command, args, &block)
|
142
142
|
results, errors = try_map do |node_key, client|
|
143
143
|
next if replica?(node_key)
|
144
144
|
|
145
|
-
client.send(method, *args,
|
145
|
+
client.send(method, *args, command, &block)
|
146
146
|
end
|
147
147
|
|
148
148
|
return results.values if errors.empty?
|
@@ -150,14 +150,14 @@ class RedisClient
|
|
150
150
|
raise ::RedisClient::Cluster::ErrorCollection, errors
|
151
151
|
end
|
152
152
|
|
153
|
-
def call_replicas(method,
|
154
|
-
return call_primaries(method,
|
153
|
+
def call_replicas(method, command, args, &block)
|
154
|
+
return call_primaries(method, command, args, &block) if replica_disabled?
|
155
155
|
|
156
156
|
replica_node_keys = @replications.values.map(&:sample)
|
157
157
|
results, errors = try_map do |node_key, client|
|
158
158
|
next if primary?(node_key) || !replica_node_keys.include?(node_key)
|
159
159
|
|
160
|
-
client.send(method, *args,
|
160
|
+
client.send(method, *args, command, &block)
|
161
161
|
end
|
162
162
|
|
163
163
|
return results.values if errors.empty?
|
@@ -165,9 +165,9 @@ class RedisClient
|
|
165
165
|
raise ::RedisClient::Cluster::ErrorCollection, errors
|
166
166
|
end
|
167
167
|
|
168
|
-
def send_ping(method,
|
168
|
+
def send_ping(method, command, args, &block)
|
169
169
|
results, errors = try_map do |_, client|
|
170
|
-
client.send(method, *args,
|
170
|
+
client.send(method, *args, command, &block)
|
171
171
|
end
|
172
172
|
|
173
173
|
return results.values if errors.empty?
|
@@ -8,27 +8,52 @@ class RedisClient
|
|
8
8
|
class Pipeline
|
9
9
|
ReplySizeError = Class.new(::RedisClient::Error)
|
10
10
|
|
11
|
-
def initialize(router)
|
11
|
+
def initialize(router, command_builder)
|
12
12
|
@router = router
|
13
|
+
@command_builder = command_builder
|
13
14
|
@grouped = Hash.new([].freeze)
|
14
15
|
@size = 0
|
15
16
|
end
|
16
17
|
|
17
|
-
def call(*
|
18
|
-
|
19
|
-
|
18
|
+
def call(*args, **kwargs, &block)
|
19
|
+
command = @command_builder.generate(args, kwargs)
|
20
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
21
|
+
@grouped[node_key] += [[@size, :call_v, command, block]]
|
20
22
|
@size += 1
|
21
23
|
end
|
22
24
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
25
|
+
def call_v(args, &block)
|
26
|
+
command = @command_builder.generate(args)
|
27
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
28
|
+
@grouped[node_key] += [[@size, :call_v, command, block]]
|
26
29
|
@size += 1
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
+
def call_once(*args, **kwargs, &block)
|
33
|
+
command = @command_builder.generate(args, kwargs)
|
34
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
35
|
+
@grouped[node_key] += [[@size, :call_once_v, command, block]]
|
36
|
+
@size += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
def call_once_v(args, &block)
|
40
|
+
command = @command_builder.generate(args)
|
41
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
42
|
+
@grouped[node_key] += [[@size, :call_once_v, command, block]]
|
43
|
+
@size += 1
|
44
|
+
end
|
45
|
+
|
46
|
+
def blocking_call(timeout, *args, **kwargs, &block)
|
47
|
+
command = @command_builder.generate(args, kwargs)
|
48
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
49
|
+
@grouped[node_key] += [[@size, :blocking_call_v, timeout, command, block]]
|
50
|
+
@size += 1
|
51
|
+
end
|
52
|
+
|
53
|
+
def blocking_call_v(timeout, args, &block)
|
54
|
+
command = @command_builder.generate(args)
|
55
|
+
node_key = @router.find_node_key(command, primary_only: true)
|
56
|
+
@grouped[node_key] += [[@size, :blocking_call_v, timeout, command, block]]
|
32
57
|
@size += 1
|
33
58
|
end
|
34
59
|
|
@@ -37,20 +62,15 @@ class RedisClient
|
|
37
62
|
end
|
38
63
|
|
39
64
|
# TODO: https://github.com/redis-rb/redis-cluster-client/issues/37 handle redirections
|
40
|
-
def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
65
|
+
def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
41
66
|
all_replies = Array.new(@size)
|
42
67
|
errors = {}
|
43
68
|
threads = @grouped.map do |k, v|
|
44
69
|
Thread.new(@router, k, v) do |router, node_key, rows|
|
45
70
|
Thread.pass
|
46
71
|
replies = router.find_node(node_key).pipelined do |pipeline|
|
47
|
-
rows.each do |row|
|
48
|
-
|
49
|
-
when :call then pipeline.call(*row[2], **row[3])
|
50
|
-
when :call_once then pipeline.call_once(*row[2], **row[3])
|
51
|
-
when :blocking_call then pipeline.blocking_call(row[2], *row[3], **row[4])
|
52
|
-
else raise NotImplementedError, row[1]
|
53
|
-
end
|
72
|
+
rows.each do |(_size, *row, block)|
|
73
|
+
pipeline.send(*row, &block)
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
@@ -3,15 +3,24 @@
|
|
3
3
|
class RedisClient
|
4
4
|
class Cluster
|
5
5
|
class PubSub
|
6
|
-
def initialize(router)
|
6
|
+
def initialize(router, command_builder)
|
7
7
|
@router = router
|
8
|
+
@command_builder = command_builder
|
8
9
|
@pubsub = nil
|
9
10
|
end
|
10
11
|
|
11
|
-
def call(*
|
12
|
+
def call(*args, **kwargs)
|
12
13
|
close
|
13
|
-
|
14
|
-
@pubsub.
|
14
|
+
command = @command_builder.generate(args, kwargs)
|
15
|
+
@pubsub = @router.assign_node(command).pubsub
|
16
|
+
@pubsub.call_v(command)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call_v(command)
|
20
|
+
close
|
21
|
+
command = @command_builder.generate(command)
|
22
|
+
@pubsub = @router.assign_node(command).pubsub
|
23
|
+
@pubsub.call_v(command)
|
15
24
|
end
|
16
25
|
|
17
26
|
def close
|
@@ -21,46 +21,80 @@ class RedisClient
|
|
21
21
|
@node = fetch_cluster_info(@config, pool: @pool, **@client_kwargs)
|
22
22
|
@command = ::RedisClient::Cluster::Command.load(@node)
|
23
23
|
@mutex = Mutex.new
|
24
|
+
@command_builder = @config.command_builder
|
24
25
|
end
|
25
26
|
|
26
|
-
def send_command(method, *args,
|
27
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
28
|
-
|
27
|
+
def send_command(method, command, *args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
29
28
|
cmd = command.first.to_s.downcase
|
30
29
|
case cmd
|
31
30
|
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
32
|
-
@node.call_all(method,
|
31
|
+
@node.call_all(method, command, args, &block).first
|
33
32
|
when 'flushall', 'flushdb'
|
34
|
-
@node.call_primaries(method,
|
35
|
-
when 'ping' then @node.send_ping(method,
|
36
|
-
when 'wait' then send_wait_command(method,
|
37
|
-
when 'keys' then @node.call_replicas(method,
|
38
|
-
when 'dbsize' then @node.call_replicas(method,
|
39
|
-
when 'scan' then scan(
|
40
|
-
when 'lastsave' then @node.call_all(method,
|
41
|
-
when 'role' then @node.call_all(method,
|
42
|
-
when 'config' then send_config_command(method,
|
43
|
-
when 'client' then send_client_command(method,
|
44
|
-
when 'cluster' then send_cluster_command(method,
|
33
|
+
@node.call_primaries(method, command, args, &block).first
|
34
|
+
when 'ping' then @node.send_ping(method, command, args, &block).first
|
35
|
+
when 'wait' then send_wait_command(method, command, args, &block)
|
36
|
+
when 'keys' then @node.call_replicas(method, command, args, &block).flatten.sort_by(&:to_s)
|
37
|
+
when 'dbsize' then @node.call_replicas(method, command, args, &block).select { |e| e.is_a?(Integer) }.sum
|
38
|
+
when 'scan' then scan(command)
|
39
|
+
when 'lastsave' then @node.call_all(method, command, args, &block).sort_by(&:to_i)
|
40
|
+
when 'role' then @node.call_all(method, command, args, &block)
|
41
|
+
when 'config' then send_config_command(method, command, args, &block)
|
42
|
+
when 'client' then send_client_command(method, command, args, &block)
|
43
|
+
when 'cluster' then send_cluster_command(method, command, args, &block)
|
45
44
|
when 'readonly', 'readwrite', 'shutdown'
|
46
45
|
raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, cmd
|
47
|
-
when 'memory' then send_memory_command(method,
|
48
|
-
when 'script' then send_script_command(method,
|
49
|
-
when 'pubsub' then send_pubsub_command(method,
|
46
|
+
when 'memory' then send_memory_command(method, command, args, &block)
|
47
|
+
when 'script' then send_script_command(method, command, args, &block)
|
48
|
+
when 'pubsub' then send_pubsub_command(method, command, args, &block)
|
50
49
|
when 'discard', 'exec', 'multi', 'unwatch'
|
51
50
|
raise ::RedisClient::Cluster::AmbiguousNodeError, cmd
|
52
51
|
else
|
53
|
-
node = assign_node(
|
54
|
-
try_send(node, method,
|
52
|
+
node = assign_node(command)
|
53
|
+
try_send(node, method, command, args, &block)
|
55
54
|
end
|
56
55
|
rescue ::RedisClient::Cluster::Node::ReloadNeeded
|
57
56
|
update_cluster_info!
|
58
57
|
raise ::RedisClient::Cluster::NodeMightBeDown
|
58
|
+
rescue ::RedisClient::Cluster::ErrorCollection => e
|
59
|
+
update_cluster_info! if e.errors.values.any? do |err|
|
60
|
+
err.message.start_with?('CLUSTERDOWN Hash slot not served')
|
61
|
+
end
|
62
|
+
raise
|
59
63
|
end
|
60
64
|
|
61
65
|
# @see https://redis.io/topics/cluster-spec#redirection-and-resharding
|
62
66
|
# Redirection and resharding
|
63
|
-
def try_send(node, method,
|
67
|
+
def try_send(node, method, command, args, retry_count: 3, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
68
|
+
node.send(method, *args, command, &block)
|
69
|
+
rescue ::RedisClient::CommandError => e
|
70
|
+
raise if retry_count <= 0
|
71
|
+
|
72
|
+
if e.message.start_with?('MOVED')
|
73
|
+
node = assign_redirection_node(e.message)
|
74
|
+
retry_count -= 1
|
75
|
+
retry
|
76
|
+
elsif e.message.start_with?('ASK')
|
77
|
+
node = assign_asking_node(e.message)
|
78
|
+
node.call('ASKING')
|
79
|
+
retry_count -= 1
|
80
|
+
retry
|
81
|
+
elsif e.message.start_with?('CLUSTERDOWN Hash slot not served')
|
82
|
+
update_cluster_info!
|
83
|
+
retry_count -= 1
|
84
|
+
retry
|
85
|
+
else
|
86
|
+
raise
|
87
|
+
end
|
88
|
+
rescue ::RedisClient::ConnectionError => e
|
89
|
+
raise if method == :blocking_call_v || (method == :blocking_call && e.is_a?(RedisClient::ReadTimeoutError))
|
90
|
+
raise if retry_count <= 0
|
91
|
+
|
92
|
+
update_cluster_info!
|
93
|
+
retry_count -= 1
|
94
|
+
retry
|
95
|
+
end
|
96
|
+
|
97
|
+
def try_delegate(node, method, *args, retry_count: 3, **kwargs, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
64
98
|
node.send(method, *args, **kwargs, &block)
|
65
99
|
rescue ::RedisClient::CommandError => e
|
66
100
|
raise if retry_count <= 0
|
@@ -74,6 +108,10 @@ class RedisClient
|
|
74
108
|
node.call('ASKING')
|
75
109
|
retry_count -= 1
|
76
110
|
retry
|
111
|
+
elsif e.message.start_with?('CLUSTERDOWN Hash slot not served')
|
112
|
+
update_cluster_info!
|
113
|
+
retry_count -= 1
|
114
|
+
retry
|
77
115
|
else
|
78
116
|
raise
|
79
117
|
end
|
@@ -86,6 +124,8 @@ class RedisClient
|
|
86
124
|
end
|
87
125
|
|
88
126
|
def scan(*command, **kwargs) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
127
|
+
command = @command_builder.generate(command, kwargs)
|
128
|
+
|
89
129
|
command[1] = ZERO_CURSOR_FOR_SCAN if command.size == 1
|
90
130
|
input_cursor = Integer(command[1])
|
91
131
|
|
@@ -99,7 +139,7 @@ class RedisClient
|
|
99
139
|
|
100
140
|
command[1] = raw_cursor.to_s
|
101
141
|
|
102
|
-
result_cursor, result_keys = client.
|
142
|
+
result_cursor, result_keys = client.call_v(command)
|
103
143
|
result_cursor = Integer(result_cursor)
|
104
144
|
|
105
145
|
client_index += 1 if result_cursor == 0
|
@@ -107,12 +147,12 @@ class RedisClient
|
|
107
147
|
[((result_cursor << 8) + client_index).to_s, result_keys]
|
108
148
|
end
|
109
149
|
|
110
|
-
def assign_node(
|
111
|
-
node_key = find_node_key(
|
150
|
+
def assign_node(command, primary_only: false)
|
151
|
+
node_key = find_node_key(command, primary_only: primary_only)
|
112
152
|
find_node(node_key)
|
113
153
|
end
|
114
154
|
|
115
|
-
def find_node_key(
|
155
|
+
def find_node_key(command, primary_only: false)
|
116
156
|
key = @command.extract_first_key(command)
|
117
157
|
slot = key.empty? ? nil : ::RedisClient::Cluster::KeySlotConverter.convert(key)
|
118
158
|
|
@@ -133,10 +173,14 @@ class RedisClient
|
|
133
173
|
retry
|
134
174
|
end
|
135
175
|
|
176
|
+
def command_exists?(name)
|
177
|
+
@command.exists?(name)
|
178
|
+
end
|
179
|
+
|
136
180
|
private
|
137
181
|
|
138
|
-
def send_wait_command(method,
|
139
|
-
@node.call_primaries(method,
|
182
|
+
def send_wait_command(method, command, args, retry_count: 3, &block)
|
183
|
+
@node.call_primaries(method, command, args, &block).select { |r| r.is_a?(Integer) }.sum
|
140
184
|
rescue ::RedisClient::Cluster::ErrorCollection => e
|
141
185
|
raise if retry_count <= 0
|
142
186
|
raise if e.errors.values.none? do |err|
|
@@ -148,76 +192,65 @@ class RedisClient
|
|
148
192
|
retry
|
149
193
|
end
|
150
194
|
|
151
|
-
def send_config_command(method,
|
152
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
153
|
-
|
195
|
+
def send_config_command(method, command, args, &block)
|
154
196
|
case command[1].to_s.downcase
|
155
197
|
when 'resetstat', 'rewrite', 'set'
|
156
|
-
@node.call_all(method,
|
157
|
-
else assign_node(
|
198
|
+
@node.call_all(method, command, args, &block).first
|
199
|
+
else assign_node(command).send(method, *args, command, &block)
|
158
200
|
end
|
159
201
|
end
|
160
202
|
|
161
|
-
def send_memory_command(method,
|
162
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
163
|
-
|
203
|
+
def send_memory_command(method, command, args, &block)
|
164
204
|
case command[1].to_s.downcase
|
165
|
-
when 'stats' then @node.call_all(method,
|
166
|
-
when 'purge' then @node.call_all(method,
|
167
|
-
else assign_node(
|
205
|
+
when 'stats' then @node.call_all(method, command, args, &block)
|
206
|
+
when 'purge' then @node.call_all(method, command, args, &block).first
|
207
|
+
else assign_node(command).send(method, *args, command, &block)
|
168
208
|
end
|
169
209
|
end
|
170
210
|
|
171
|
-
def send_client_command(method,
|
172
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
173
|
-
|
211
|
+
def send_client_command(method, command, args, &block)
|
174
212
|
case command[1].to_s.downcase
|
175
|
-
when 'list' then @node.call_all(method,
|
213
|
+
when 'list' then @node.call_all(method, command, args, &block).flatten
|
176
214
|
when 'pause', 'reply', 'setname'
|
177
|
-
@node.call_all(method,
|
178
|
-
else assign_node(
|
215
|
+
@node.call_all(method, command, args, &block).first
|
216
|
+
else assign_node(command).send(method, *args, command, &block)
|
179
217
|
end
|
180
218
|
end
|
181
219
|
|
182
|
-
def send_cluster_command(method,
|
183
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
220
|
+
def send_cluster_command(method, command, args, &block) # rubocop:disable Metrics/MethodLength
|
184
221
|
subcommand = command[1].to_s.downcase
|
185
222
|
|
186
223
|
case subcommand
|
187
224
|
when 'addslots', 'delslots', 'failover', 'forget', 'meet', 'replicate',
|
188
225
|
'reset', 'set-config-epoch', 'setslot'
|
189
226
|
raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, ['cluster', subcommand]
|
190
|
-
when 'saveconfig' then @node.call_all(method,
|
227
|
+
when 'saveconfig' then @node.call_all(method, command, args, &block).first
|
191
228
|
when 'getkeysinslot'
|
192
229
|
raise ArgumentError, command.join(' ') if command.size != 4
|
193
230
|
|
194
|
-
find_node(@node.find_node_key_of_replica(command[2])).send(method, *args,
|
195
|
-
else assign_node(
|
231
|
+
find_node(@node.find_node_key_of_replica(command[2])).send(method, *args, command, &block)
|
232
|
+
else assign_node(command).send(method, *args, command, &block)
|
196
233
|
end
|
197
234
|
end
|
198
235
|
|
199
|
-
def send_script_command(method,
|
200
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
201
|
-
|
236
|
+
def send_script_command(method, command, args, &block)
|
202
237
|
case command[1].to_s.downcase
|
203
238
|
when 'debug', 'kill'
|
204
|
-
@node.call_all(method,
|
239
|
+
@node.call_all(method, command, args, &block).first
|
205
240
|
when 'flush', 'load'
|
206
|
-
@node.call_primaries(method,
|
207
|
-
else assign_node(
|
241
|
+
@node.call_primaries(method, command, args, &block).first
|
242
|
+
else assign_node(command).send(method, *args, command, &block)
|
208
243
|
end
|
209
244
|
end
|
210
245
|
|
211
|
-
def send_pubsub_command(method,
|
212
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
213
|
-
|
246
|
+
def send_pubsub_command(method, command, args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
214
247
|
case command[1].to_s.downcase
|
215
|
-
when 'channels' then @node.call_all(method,
|
248
|
+
when 'channels' then @node.call_all(method, command, args, &block).flatten.uniq.sort_by(&:to_s)
|
216
249
|
when 'numsub'
|
217
|
-
@node.call_all(method,
|
250
|
+
@node.call_all(method, command, args, &block).reject(&:empty?).map { |e| Hash[*e] }
|
218
251
|
.reduce({}) { |a, e| a.merge(e) { |_, v1, v2| v1 + v2 } }
|
219
|
-
when 'numpat' then @node.call_all(method,
|
220
|
-
else assign_node(
|
252
|
+
when 'numpat' then @node.call_all(method, command, args, &block).select { |e| e.is_a?(Integer) }.sum
|
253
|
+
else assign_node(command).send(method, *args, command, &block)
|
221
254
|
end
|
222
255
|
end
|
223
256
|
|
@@ -244,7 +277,7 @@ class RedisClient
|
|
244
277
|
def update_cluster_info!
|
245
278
|
@mutex.synchronize do
|
246
279
|
begin
|
247
|
-
@node.
|
280
|
+
@node.each(&:close)
|
248
281
|
rescue ::RedisClient::Cluster::ErrorCollection
|
249
282
|
# ignore
|
250
283
|
end
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'redis_client'
|
4
3
|
require 'redis_client/cluster/pipeline'
|
5
4
|
require 'redis_client/cluster/pub_sub'
|
6
5
|
require 'redis_client/cluster/router'
|
@@ -9,24 +8,46 @@ class RedisClient
|
|
9
8
|
class Cluster
|
10
9
|
ZERO_CURSOR_FOR_SCAN = '0'
|
11
10
|
|
11
|
+
attr_reader :config
|
12
|
+
|
12
13
|
def initialize(config, pool: nil, **kwargs)
|
14
|
+
@config = config
|
13
15
|
@router = ::RedisClient::Cluster::Router.new(config, pool: pool, **kwargs)
|
16
|
+
@command_builder = config.command_builder
|
14
17
|
end
|
15
18
|
|
16
19
|
def inspect
|
17
20
|
"#<#{self.class.name} #{@router.node.node_keys.join(', ')}>"
|
18
21
|
end
|
19
22
|
|
20
|
-
def call(*
|
21
|
-
@
|
23
|
+
def call(*args, **kwargs, &block)
|
24
|
+
command = @command_builder.generate(args, kwargs)
|
25
|
+
@router.send_command(:call_v, command, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call_v(command, &block)
|
29
|
+
command = @command_builder.generate(command)
|
30
|
+
@router.send_command(:call_v, command, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def call_once(*args, **kwargs, &block)
|
34
|
+
command = @command_builder.generate(args, kwargs)
|
35
|
+
@router.send_command(:call_once_v, command, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def call_once_v(command, &block)
|
39
|
+
command = @command_builder.generate(command)
|
40
|
+
@router.send_command(:call_once_v, command, &block)
|
22
41
|
end
|
23
42
|
|
24
|
-
def
|
25
|
-
@
|
43
|
+
def blocking_call(timeout, *args, **kwargs, &block)
|
44
|
+
command = @command_builder.generate(args, kwargs)
|
45
|
+
@router.send_command(:blocking_call_v, command, timeout, &block)
|
26
46
|
end
|
27
47
|
|
28
|
-
def
|
29
|
-
@
|
48
|
+
def blocking_call_v(timeout, command, &block)
|
49
|
+
command = @command_builder.generate(command)
|
50
|
+
@router.send_command(:blocking_call_v, command, timeout, &block)
|
30
51
|
end
|
31
52
|
|
32
53
|
def scan(*args, **kwargs, &block)
|
@@ -41,22 +62,22 @@ class RedisClient
|
|
41
62
|
end
|
42
63
|
|
43
64
|
def sscan(key, *args, **kwargs, &block)
|
44
|
-
node = @router.assign_node('SSCAN', key)
|
45
|
-
@router.
|
65
|
+
node = @router.assign_node(['SSCAN', key])
|
66
|
+
@router.try_delegate(node, :sscan, key, *args, **kwargs, &block)
|
46
67
|
end
|
47
68
|
|
48
69
|
def hscan(key, *args, **kwargs, &block)
|
49
|
-
node = @router.assign_node('HSCAN', key)
|
50
|
-
@router.
|
70
|
+
node = @router.assign_node(['HSCAN', key])
|
71
|
+
@router.try_delegate(node, :hscan, key, *args, **kwargs, &block)
|
51
72
|
end
|
52
73
|
|
53
74
|
def zscan(key, *args, **kwargs, &block)
|
54
|
-
node = @router.assign_node('ZSCAN', key)
|
55
|
-
@router.
|
75
|
+
node = @router.assign_node(['ZSCAN', key])
|
76
|
+
@router.try_delegate(node, :zscan, key, *args, **kwargs, &block)
|
56
77
|
end
|
57
78
|
|
58
79
|
def pipelined
|
59
|
-
pipeline = ::RedisClient::Cluster::Pipeline.new(@router)
|
80
|
+
pipeline = ::RedisClient::Cluster::Pipeline.new(@router, @command_builder)
|
60
81
|
yield pipeline
|
61
82
|
return [] if pipeline.empty? == 0
|
62
83
|
|
@@ -64,12 +85,30 @@ class RedisClient
|
|
64
85
|
end
|
65
86
|
|
66
87
|
def pubsub
|
67
|
-
::RedisClient::Cluster::PubSub.new(@router)
|
88
|
+
::RedisClient::Cluster::PubSub.new(@router, @command_builder)
|
68
89
|
end
|
69
90
|
|
70
91
|
def close
|
71
|
-
@router.node.
|
92
|
+
@router.node.each(&:close)
|
72
93
|
nil
|
73
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def method_missing(name, *args, **kwargs, &block)
|
99
|
+
if @router.command_exists?(name)
|
100
|
+
args.unshift(name)
|
101
|
+
command = @command_builder.generate(args, kwargs)
|
102
|
+
return @router.send_command(:call_v, command, &block)
|
103
|
+
end
|
104
|
+
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def respond_to_missing?(name, include_private = false)
|
109
|
+
return true if @router.command_exists?(name)
|
110
|
+
|
111
|
+
super
|
112
|
+
end
|
74
113
|
end
|
75
114
|
end
|
@@ -4,6 +4,7 @@ require 'uri'
|
|
4
4
|
require 'redis_client'
|
5
5
|
require 'redis_client/cluster'
|
6
6
|
require 'redis_client/cluster/node_key'
|
7
|
+
require 'redis_client/command_builder'
|
7
8
|
|
8
9
|
class RedisClient
|
9
10
|
class ClusterConfig
|
@@ -19,12 +20,16 @@ class RedisClient
|
|
19
20
|
|
20
21
|
InvalidClientConfigError = Class.new(::RedisClient::Error)
|
21
22
|
|
22
|
-
|
23
|
+
attr_reader :command_builder, :client_config
|
24
|
+
|
25
|
+
def initialize(nodes: DEFAULT_NODES, replica: false, client_implementation: Cluster, fixed_hostname: '', **client_config)
|
23
26
|
@replica = true & replica
|
24
27
|
@fixed_hostname = fixed_hostname.to_s
|
25
28
|
@node_configs = build_node_configs(nodes.dup)
|
26
29
|
client_config = client_config.reject { |k, _| IGNORE_GENERIC_CONFIG_KEYS.include?(k) }
|
30
|
+
@command_builder = client_config.fetch(:command_builder, ::RedisClient::CommandBuilder)
|
27
31
|
@client_config = merge_generic_config(client_config, @node_configs)
|
32
|
+
@client_implementation = client_implementation
|
28
33
|
@mutex = Mutex.new
|
29
34
|
end
|
30
35
|
|
@@ -32,12 +37,16 @@ class RedisClient
|
|
32
37
|
"#<#{self.class.name} #{per_node_key.values}>"
|
33
38
|
end
|
34
39
|
|
40
|
+
def read_timeout
|
41
|
+
@client_config[:read_timeout] || @client_config[:timeout] || RedisClient::Config::DEFAULT_TIMEOUT
|
42
|
+
end
|
43
|
+
|
35
44
|
def new_pool(size: 5, timeout: 5, **kwargs)
|
36
|
-
|
45
|
+
@client_implementation.new(self, pool: { size: size, timeout: timeout }, **kwargs)
|
37
46
|
end
|
38
47
|
|
39
48
|
def new_client(**kwargs)
|
40
|
-
|
49
|
+
@client_implementation.new(self, **kwargs)
|
41
50
|
end
|
42
51
|
|
43
52
|
def per_node_key
|
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
|
4
|
+
version: 0.2.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: 2022-
|
11
|
+
date: 2022-08-17 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.6'
|
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.6'
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- proxy0721@gmail.com
|
@@ -31,6 +31,7 @@ executables: []
|
|
31
31
|
extensions: []
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
|
+
- lib/redis-cluster-client.rb
|
34
35
|
- lib/redis_client/cluster.rb
|
35
36
|
- lib/redis_client/cluster/command.rb
|
36
37
|
- lib/redis_client/cluster/errors.rb
|