redis-cluster-client 0.1.0 → 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/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 +82 -74
- data/lib/redis_client/cluster.rb +39 -17
- data/lib/redis_client/cluster_config.rb +9 -4
- 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
|
@@ -20,40 +20,37 @@ class RedisClient
|
|
20
20
|
@client_kwargs = kwargs
|
21
21
|
@node = fetch_cluster_info(@config, pool: @pool, **@client_kwargs)
|
22
22
|
@command = ::RedisClient::Cluster::Command.load(@node)
|
23
|
-
@command_builder = @config.command_builder
|
24
23
|
@mutex = Mutex.new
|
24
|
+
@command_builder = @config.command_builder
|
25
25
|
end
|
26
26
|
|
27
|
-
def send_command(method, *args,
|
28
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
29
|
-
command = @command_builder.generate!(command, kwargs)
|
30
|
-
|
27
|
+
def send_command(method, command, *args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
31
28
|
cmd = command.first.to_s.downcase
|
32
29
|
case cmd
|
33
30
|
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
34
|
-
@node.call_all(method,
|
31
|
+
@node.call_all(method, command, args, &block).first
|
35
32
|
when 'flushall', 'flushdb'
|
36
|
-
@node.call_primaries(method,
|
37
|
-
when 'ping' then @node.send_ping(method,
|
38
|
-
when 'wait' then send_wait_command(method,
|
39
|
-
when 'keys' then @node.call_replicas(method,
|
40
|
-
when 'dbsize' then @node.call_replicas(method,
|
41
|
-
when 'scan' then scan(
|
42
|
-
when 'lastsave' then @node.call_all(method,
|
43
|
-
when 'role' then @node.call_all(method,
|
44
|
-
when 'config' then send_config_command(method,
|
45
|
-
when 'client' then send_client_command(method,
|
46
|
-
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)
|
47
44
|
when 'readonly', 'readwrite', 'shutdown'
|
48
45
|
raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, cmd
|
49
|
-
when 'memory' then send_memory_command(method,
|
50
|
-
when 'script' then send_script_command(method,
|
51
|
-
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)
|
52
49
|
when 'discard', 'exec', 'multi', 'unwatch'
|
53
50
|
raise ::RedisClient::Cluster::AmbiguousNodeError, cmd
|
54
51
|
else
|
55
|
-
node = assign_node(
|
56
|
-
try_send(node, method,
|
52
|
+
node = assign_node(command)
|
53
|
+
try_send(node, method, command, args, &block)
|
57
54
|
end
|
58
55
|
rescue ::RedisClient::Cluster::Node::ReloadNeeded
|
59
56
|
update_cluster_info!
|
@@ -67,7 +64,37 @@ class RedisClient
|
|
67
64
|
|
68
65
|
# @see https://redis.io/topics/cluster-spec#redirection-and-resharding
|
69
66
|
# Redirection and resharding
|
70
|
-
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
|
71
98
|
node.send(method, *args, **kwargs, &block)
|
72
99
|
rescue ::RedisClient::CommandError => e
|
73
100
|
raise if retry_count <= 0
|
@@ -97,7 +124,7 @@ class RedisClient
|
|
97
124
|
end
|
98
125
|
|
99
126
|
def scan(*command, **kwargs) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
100
|
-
command = @command_builder.generate
|
127
|
+
command = @command_builder.generate(command, kwargs)
|
101
128
|
|
102
129
|
command[1] = ZERO_CURSOR_FOR_SCAN if command.size == 1
|
103
130
|
input_cursor = Integer(command[1])
|
@@ -112,7 +139,7 @@ class RedisClient
|
|
112
139
|
|
113
140
|
command[1] = raw_cursor.to_s
|
114
141
|
|
115
|
-
result_cursor, result_keys = client.
|
142
|
+
result_cursor, result_keys = client.call_v(command)
|
116
143
|
result_cursor = Integer(result_cursor)
|
117
144
|
|
118
145
|
client_index += 1 if result_cursor == 0
|
@@ -120,14 +147,12 @@ class RedisClient
|
|
120
147
|
[((result_cursor << 8) + client_index).to_s, result_keys]
|
121
148
|
end
|
122
149
|
|
123
|
-
def assign_node(
|
124
|
-
node_key = find_node_key(
|
150
|
+
def assign_node(command, primary_only: false)
|
151
|
+
node_key = find_node_key(command, primary_only: primary_only)
|
125
152
|
find_node(node_key)
|
126
153
|
end
|
127
154
|
|
128
|
-
def find_node_key(
|
129
|
-
command = @command_builder.generate!(command, kwargs)
|
130
|
-
|
155
|
+
def find_node_key(command, primary_only: false)
|
131
156
|
key = @command.extract_first_key(command)
|
132
157
|
slot = key.empty? ? nil : ::RedisClient::Cluster::KeySlotConverter.convert(key)
|
133
158
|
|
@@ -154,8 +179,8 @@ class RedisClient
|
|
154
179
|
|
155
180
|
private
|
156
181
|
|
157
|
-
def send_wait_command(method,
|
158
|
-
@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
|
159
184
|
rescue ::RedisClient::Cluster::ErrorCollection => e
|
160
185
|
raise if retry_count <= 0
|
161
186
|
raise if e.errors.values.none? do |err|
|
@@ -167,82 +192,65 @@ class RedisClient
|
|
167
192
|
retry
|
168
193
|
end
|
169
194
|
|
170
|
-
def send_config_command(method,
|
171
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
172
|
-
command = @command_builder.generate!(command, kwargs)
|
173
|
-
|
195
|
+
def send_config_command(method, command, args, &block)
|
174
196
|
case command[1].to_s.downcase
|
175
197
|
when 'resetstat', 'rewrite', 'set'
|
176
|
-
@node.call_all(method,
|
177
|
-
else assign_node(
|
198
|
+
@node.call_all(method, command, args, &block).first
|
199
|
+
else assign_node(command).send(method, *args, command, &block)
|
178
200
|
end
|
179
201
|
end
|
180
202
|
|
181
|
-
def send_memory_command(method,
|
182
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
183
|
-
command = @command_builder.generate!(command, kwargs)
|
184
|
-
|
203
|
+
def send_memory_command(method, command, args, &block)
|
185
204
|
case command[1].to_s.downcase
|
186
|
-
when 'stats' then @node.call_all(method,
|
187
|
-
when 'purge' then @node.call_all(method,
|
188
|
-
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)
|
189
208
|
end
|
190
209
|
end
|
191
210
|
|
192
|
-
def send_client_command(method,
|
193
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
194
|
-
command = @command_builder.generate!(command, kwargs)
|
195
|
-
|
211
|
+
def send_client_command(method, command, args, &block)
|
196
212
|
case command[1].to_s.downcase
|
197
|
-
when 'list' then @node.call_all(method,
|
213
|
+
when 'list' then @node.call_all(method, command, args, &block).flatten
|
198
214
|
when 'pause', 'reply', 'setname'
|
199
|
-
@node.call_all(method,
|
200
|
-
else assign_node(
|
215
|
+
@node.call_all(method, command, args, &block).first
|
216
|
+
else assign_node(command).send(method, *args, command, &block)
|
201
217
|
end
|
202
218
|
end
|
203
219
|
|
204
|
-
def send_cluster_command(method,
|
205
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
206
|
-
command = @command_builder.generate!(command, kwargs)
|
220
|
+
def send_cluster_command(method, command, args, &block) # rubocop:disable Metrics/MethodLength
|
207
221
|
subcommand = command[1].to_s.downcase
|
208
222
|
|
209
223
|
case subcommand
|
210
224
|
when 'addslots', 'delslots', 'failover', 'forget', 'meet', 'replicate',
|
211
225
|
'reset', 'set-config-epoch', 'setslot'
|
212
226
|
raise ::RedisClient::Cluster::OrchestrationCommandNotSupported, ['cluster', subcommand]
|
213
|
-
when 'saveconfig' then @node.call_all(method,
|
227
|
+
when 'saveconfig' then @node.call_all(method, command, args, &block).first
|
214
228
|
when 'getkeysinslot'
|
215
229
|
raise ArgumentError, command.join(' ') if command.size != 4
|
216
230
|
|
217
|
-
find_node(@node.find_node_key_of_replica(command[2])).send(method, *args,
|
218
|
-
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)
|
219
233
|
end
|
220
234
|
end
|
221
235
|
|
222
|
-
def send_script_command(method,
|
223
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
224
|
-
command = @command_builder.generate!(command, kwargs)
|
225
|
-
|
236
|
+
def send_script_command(method, command, args, &block)
|
226
237
|
case command[1].to_s.downcase
|
227
238
|
when 'debug', 'kill'
|
228
|
-
@node.call_all(method,
|
239
|
+
@node.call_all(method, command, args, &block).first
|
229
240
|
when 'flush', 'load'
|
230
|
-
@node.call_primaries(method,
|
231
|
-
else assign_node(
|
241
|
+
@node.call_primaries(method, command, args, &block).first
|
242
|
+
else assign_node(command).send(method, *args, command, &block)
|
232
243
|
end
|
233
244
|
end
|
234
245
|
|
235
|
-
def send_pubsub_command(method,
|
236
|
-
command = method == :blocking_call && args.size > 1 ? args[1..] : args
|
237
|
-
command = @command_builder.generate!(command, kwargs)
|
238
|
-
|
246
|
+
def send_pubsub_command(method, command, args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
239
247
|
case command[1].to_s.downcase
|
240
|
-
when 'channels' then @node.call_all(method,
|
248
|
+
when 'channels' then @node.call_all(method, command, args, &block).flatten.uniq.sort_by(&:to_s)
|
241
249
|
when 'numsub'
|
242
|
-
@node.call_all(method,
|
250
|
+
@node.call_all(method, command, args, &block).reject(&:empty?).map { |e| Hash[*e] }
|
243
251
|
.reduce({}) { |a, e| a.merge(e) { |_, v1, v2| v1 + v2 } }
|
244
|
-
when 'numpat' then @node.call_all(method,
|
245
|
-
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)
|
246
254
|
end
|
247
255
|
end
|
248
256
|
|
@@ -269,7 +277,7 @@ class RedisClient
|
|
269
277
|
def update_cluster_info!
|
270
278
|
@mutex.synchronize do
|
271
279
|
begin
|
272
|
-
@node.
|
280
|
+
@node.each(&:close)
|
273
281
|
rescue ::RedisClient::Cluster::ErrorCollection
|
274
282
|
# ignore
|
275
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,11 +85,11 @@ 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
|
74
95
|
|
@@ -77,7 +98,8 @@ class RedisClient
|
|
77
98
|
def method_missing(name, *args, **kwargs, &block)
|
78
99
|
if @router.command_exists?(name)
|
79
100
|
args.unshift(name)
|
80
|
-
|
101
|
+
command = @command_builder.generate(args, kwargs)
|
102
|
+
return @router.send_command(:call_v, command, &block)
|
81
103
|
end
|
82
104
|
|
83
105
|
super
|
@@ -20,15 +20,16 @@ class RedisClient
|
|
20
20
|
|
21
21
|
InvalidClientConfigError = Class.new(::RedisClient::Error)
|
22
22
|
|
23
|
-
attr_reader :command_builder
|
23
|
+
attr_reader :command_builder, :client_config
|
24
24
|
|
25
|
-
def initialize(nodes: DEFAULT_NODES, replica: false, fixed_hostname: '', **client_config)
|
25
|
+
def initialize(nodes: DEFAULT_NODES, replica: false, client_implementation: Cluster, fixed_hostname: '', **client_config)
|
26
26
|
@replica = true & replica
|
27
27
|
@fixed_hostname = fixed_hostname.to_s
|
28
28
|
@node_configs = build_node_configs(nodes.dup)
|
29
29
|
client_config = client_config.reject { |k, _| IGNORE_GENERIC_CONFIG_KEYS.include?(k) }
|
30
30
|
@command_builder = client_config.fetch(:command_builder, ::RedisClient::CommandBuilder)
|
31
31
|
@client_config = merge_generic_config(client_config, @node_configs)
|
32
|
+
@client_implementation = client_implementation
|
32
33
|
@mutex = Mutex.new
|
33
34
|
end
|
34
35
|
|
@@ -36,12 +37,16 @@ class RedisClient
|
|
36
37
|
"#<#{self.class.name} #{per_node_key.values}>"
|
37
38
|
end
|
38
39
|
|
40
|
+
def read_timeout
|
41
|
+
@client_config[:read_timeout] || @client_config[:timeout] || RedisClient::Config::DEFAULT_TIMEOUT
|
42
|
+
end
|
43
|
+
|
39
44
|
def new_pool(size: 5, timeout: 5, **kwargs)
|
40
|
-
|
45
|
+
@client_implementation.new(self, pool: { size: size, timeout: timeout }, **kwargs)
|
41
46
|
end
|
42
47
|
|
43
48
|
def new_client(**kwargs)
|
44
|
-
|
49
|
+
@client_implementation.new(self, **kwargs)
|
45
50
|
end
|
46
51
|
|
47
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.
|
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
|