redis-cluster-client 0.16.5 → 0.16.6
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_client/cluster/command.rb +86 -24
- data/lib/redis_client/cluster/node.rb +18 -1
- data/lib/redis_client/cluster/router.rb +93 -40
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 201f719d07b33c0df8cde529564564e2993495a7817419730b6699047e40c068
|
|
4
|
+
data.tar.gz: 45790a9f41cd3708e8ffc7c2729e767204711c966cf9dd19aed419b7abc9fb5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '085310367927882a2e2d6547419ca4edc254ea2296411ed0c8f0f7352b48d98c54a6e005cc4e11ab0b5455810fa9b086dfefa9786373f926de520c7972bae5fe'
|
|
7
|
+
data.tar.gz: 5d3db4f8ecee72af9d44c239bab164c581b4983c21a7eca1063d3724f0f70d1ed5ef73d5b141a43d34a32edc6419210fd839c0d48b61efac18ac88d5306a5a03
|
|
@@ -9,15 +9,25 @@ class RedisClient
|
|
|
9
9
|
class Command
|
|
10
10
|
EMPTY_STRING = ''
|
|
11
11
|
EMPTY_HASH = {}.freeze
|
|
12
|
+
EMPTY_POLICIES = [nil, nil].freeze
|
|
13
|
+
REQUEST_POLICY_PREFIX = 'request_policy:'
|
|
14
|
+
RESPONSE_POLICY_PREFIX = 'response_policy:'
|
|
15
|
+
SUBCOMMAND_DELIMITER = '|'
|
|
12
16
|
|
|
13
|
-
private_constant :EMPTY_HASH
|
|
17
|
+
private_constant :EMPTY_HASH, :EMPTY_POLICIES, :REQUEST_POLICY_PREFIX,
|
|
18
|
+
:RESPONSE_POLICY_PREFIX, :SUBCOMMAND_DELIMITER
|
|
14
19
|
|
|
20
|
+
# @see https://redis.io/docs/latest/commands/command/ The reply of the COMMAND command
|
|
21
|
+
# @see https://redis.io/docs/latest/develop/reference/command-tips/ Command tips
|
|
15
22
|
Spec = Struct.new(
|
|
16
23
|
'RedisCommandSpec',
|
|
17
24
|
:first_key_position,
|
|
18
25
|
:key_step,
|
|
19
26
|
:write?,
|
|
20
27
|
:readonly?,
|
|
28
|
+
:request_policy,
|
|
29
|
+
:response_policy,
|
|
30
|
+
:subcommands,
|
|
21
31
|
keyword_init: true
|
|
22
32
|
) do
|
|
23
33
|
def extract_first_key(command)
|
|
@@ -86,40 +96,92 @@ class RedisClient
|
|
|
86
96
|
|
|
87
97
|
private
|
|
88
98
|
|
|
89
|
-
def parse_command_reply(rows)
|
|
99
|
+
def parse_command_reply(rows)
|
|
90
100
|
rows&.each_with_object({}) do |row, acc|
|
|
91
101
|
next if row.first.nil?
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
pos = case row.first
|
|
96
|
-
when 'eval', 'evalsha', 'zinterstore', 'zunionstore' then 3
|
|
97
|
-
when 'object', 'xgroup' then 2
|
|
98
|
-
when 'migrate', 'xread', 'xreadgroup' then 0
|
|
99
|
-
else row[3]
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
writable = case row.first
|
|
103
|
-
when 'xgroup' then true
|
|
104
|
-
else row[2].include?('write')
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
acc[row.first] = ::RedisClient::Cluster::Command::Spec.new(
|
|
108
|
-
first_key_position: pos,
|
|
109
|
-
key_step: row[5],
|
|
110
|
-
write?: writable,
|
|
111
|
-
readonly?: row[2].include?('readonly')
|
|
112
|
-
).freeze
|
|
103
|
+
acc[row.first] = build_spec(row)
|
|
113
104
|
end.freeze || EMPTY_HASH
|
|
114
105
|
end
|
|
106
|
+
|
|
107
|
+
def build_spec(row)
|
|
108
|
+
request_policy, response_policy = parse_tips(row[7])
|
|
109
|
+
|
|
110
|
+
::RedisClient::Cluster::Command::Spec.new(
|
|
111
|
+
first_key_position: parse_first_key_position(row),
|
|
112
|
+
key_step: row[5],
|
|
113
|
+
write?: parse_writability(row),
|
|
114
|
+
readonly?: row[2].include?('readonly'),
|
|
115
|
+
request_policy: request_policy,
|
|
116
|
+
response_policy: response_policy,
|
|
117
|
+
subcommands: parse_subcommands(row[9])
|
|
118
|
+
).freeze
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# The redis 6.2 or earlier doesn't include the information of the subcommands in the reply.
|
|
122
|
+
# These hard-coded positions are the fallback for such old versions.
|
|
123
|
+
def parse_first_key_position(row)
|
|
124
|
+
case row.first
|
|
125
|
+
when 'eval', 'evalsha', 'zinterstore', 'zunionstore' then 3
|
|
126
|
+
when 'object', 'xgroup' then 2
|
|
127
|
+
when 'migrate', 'xread', 'xreadgroup' then 0
|
|
128
|
+
else row[3]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def parse_writability(row)
|
|
133
|
+
case row.first
|
|
134
|
+
when 'xgroup' then true
|
|
135
|
+
else row[2].include?('write')
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# The command tips are available in the redis 7.0 or later.
|
|
140
|
+
def parse_tips(tips)
|
|
141
|
+
return EMPTY_POLICIES if tips.nil? || tips.empty?
|
|
142
|
+
|
|
143
|
+
request_policy = response_policy = nil
|
|
144
|
+
|
|
145
|
+
tips.each do |tip|
|
|
146
|
+
if tip.start_with?(REQUEST_POLICY_PREFIX)
|
|
147
|
+
request_policy = -tip[REQUEST_POLICY_PREFIX.size..]
|
|
148
|
+
elsif tip.start_with?(RESPONSE_POLICY_PREFIX)
|
|
149
|
+
response_policy = -tip[RESPONSE_POLICY_PREFIX.size..]
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
[request_policy, response_policy]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# The information of the subcommands is available in the redis 7.0 or later.
|
|
157
|
+
# A container command such as XINFO reports its key positions per subcommand.
|
|
158
|
+
def parse_subcommands(rows)
|
|
159
|
+
return if rows.nil? || rows.empty?
|
|
160
|
+
|
|
161
|
+
rows.each_with_object({}) do |row, acc|
|
|
162
|
+
name = row.first
|
|
163
|
+
next if name.nil?
|
|
164
|
+
|
|
165
|
+
# The server replies with a full name of the subcommand such as `xinfo|stream`.
|
|
166
|
+
i = name.index(SUBCOMMAND_DELIMITER)
|
|
167
|
+
acc[i.nil? ? name : name[(i + 1)..]] = build_spec(row)
|
|
168
|
+
end.freeze
|
|
169
|
+
end
|
|
115
170
|
end
|
|
116
171
|
|
|
117
172
|
def initialize(commands)
|
|
118
173
|
@commands = commands || EMPTY_HASH
|
|
119
174
|
end
|
|
120
175
|
|
|
121
|
-
def get_spec(
|
|
122
|
-
|
|
176
|
+
def get_spec(command) # rubocop:disable Metrics/AbcSize
|
|
177
|
+
name = command.first
|
|
178
|
+
spec = @commands[name] || @commands[name.to_s.downcase(:ascii)]
|
|
179
|
+
return spec if spec.nil? || spec.subcommands.nil?
|
|
180
|
+
|
|
181
|
+
subcommand = command[1]
|
|
182
|
+
return spec if subcommand.nil?
|
|
183
|
+
|
|
184
|
+
spec.subcommands[subcommand] || spec.subcommands[subcommand.to_s.downcase(:ascii)] || spec
|
|
123
185
|
end
|
|
124
186
|
|
|
125
187
|
def exists?(name)
|
|
@@ -141,6 +141,16 @@ class RedisClient
|
|
|
141
141
|
call_multiple_nodes!(@topology.replica_clients, method, command, args, &block)
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
+
# for the `response_policy:one_succeeded` command tip
|
|
145
|
+
def call_all_leniently(method, command, args, &block)
|
|
146
|
+
call_multiple_nodes_leniently(@topology.clients, method, command, args, &block)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# for the `response_policy:one_succeeded` command tip
|
|
150
|
+
def call_primaries_leniently(method, command, args, &block)
|
|
151
|
+
call_multiple_nodes_leniently(@topology.primary_clients, method, command, args, &block)
|
|
152
|
+
end
|
|
153
|
+
|
|
144
154
|
def send_ping(method, command, args, &block)
|
|
145
155
|
result_values, errors = call_multiple_nodes(@topology.clients, method, command, args, &block)
|
|
146
156
|
return result_values if errors.nil? || errors.empty?
|
|
@@ -265,6 +275,13 @@ class RedisClient
|
|
|
265
275
|
raise ::RedisClient::Cluster::ErrorCollection.with_errors(errors)
|
|
266
276
|
end
|
|
267
277
|
|
|
278
|
+
def call_multiple_nodes_leniently(clients, method, command, args, &block)
|
|
279
|
+
result_values, errors = call_multiple_nodes(clients, method, command, args, &block)
|
|
280
|
+
return result_values unless result_values.nil? || result_values.empty?
|
|
281
|
+
|
|
282
|
+
raise ::RedisClient::Cluster::ErrorCollection.with_errors(errors)
|
|
283
|
+
end
|
|
284
|
+
|
|
268
285
|
def try_map(clients, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
269
286
|
return [{}, {}] if clients.empty?
|
|
270
287
|
|
|
@@ -403,7 +420,7 @@ class RedisClient
|
|
|
403
420
|
shard = shard.each_slice(2).to_h if resp2
|
|
404
421
|
nodes = shard.fetch('nodes')
|
|
405
422
|
nodes = nodes.map { |n| n.each_slice(2).to_h } if resp2
|
|
406
|
-
primary_id = nodes.find { |n| n.fetch('role') == 'master' }
|
|
423
|
+
primary_id = nodes.find { |n| n.fetch('role') == 'master' }&.fetch('id') || EMPTY_STRING
|
|
407
424
|
|
|
408
425
|
nodes.each do |node|
|
|
409
426
|
host = pick_shard_host(node)
|
|
@@ -17,38 +17,39 @@ class RedisClient
|
|
|
17
17
|
class Router
|
|
18
18
|
ZERO_CURSOR_FOR_SCAN = '0'
|
|
19
19
|
TSF = ->(f, x) { f.nil? ? x : f.call(x) }.curry
|
|
20
|
+
RoutingAction = Struct.new('RedisCommandRoutingAction', :method_name, :reply_transformer, keyword_init: true)
|
|
21
|
+
PICK_FIRST = ->(reply) { reply.first } # rubocop:disable Style/SymbolProc
|
|
22
|
+
FLATTEN_STRINGS = ->(reply) { reply.flatten.sort_by(&:to_s) }
|
|
23
|
+
SUM_NUM = ->(reply) { reply.select { |e| e.is_a?(Integer) }.sum }
|
|
24
|
+
SORT_NUMBERS = ->(reply) { reply.sort_by(&:to_i) }
|
|
25
|
+
if Object.const_defined?(:Ractor, false) && Ractor.respond_to?(:make_shareable)
|
|
26
|
+
Ractor.make_shareable(PICK_FIRST)
|
|
27
|
+
Ractor.make_shareable(FLATTEN_STRINGS)
|
|
28
|
+
Ractor.make_shareable(SUM_NUM)
|
|
29
|
+
Ractor.make_shareable(SORT_NUMBERS)
|
|
30
|
+
end
|
|
20
31
|
DEDICATED_ACTIONS = lambda do # rubocop:disable Metrics/BlockLength
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Ractor.make_shareable(pick_first)
|
|
28
|
-
Ractor.make_shareable(flatten_strings)
|
|
29
|
-
Ractor.make_shareable(sum_num)
|
|
30
|
-
Ractor.make_shareable(sort_numbers)
|
|
31
|
-
end
|
|
32
|
-
multiple_key_action = action.new(method_name: :send_multiple_keys_command)
|
|
33
|
-
all_node_first_action = action.new(method_name: :send_command_to_all_nodes, reply_transformer: pick_first)
|
|
34
|
-
primary_first_action = action.new(method_name: :send_command_to_primaries, reply_transformer: pick_first)
|
|
35
|
-
not_supported_action = action.new(method_name: :fail_not_supported_command)
|
|
36
|
-
keyless_action = action.new(method_name: :fail_keyless_command)
|
|
32
|
+
multiple_key_action = RoutingAction.new(method_name: :send_multiple_keys_command)
|
|
33
|
+
all_node_first_action = RoutingAction.new(method_name: :send_command_to_all_nodes, reply_transformer: PICK_FIRST)
|
|
34
|
+
primary_first_action = RoutingAction.new(method_name: :send_command_to_primaries, reply_transformer: PICK_FIRST)
|
|
35
|
+
not_supported_action = RoutingAction.new(method_name: :fail_not_supported_command)
|
|
36
|
+
keyless_action = RoutingAction.new(method_name: :fail_keyless_command)
|
|
37
|
+
single_node_action = RoutingAction.new(method_name: :assign_node_and_send_command)
|
|
37
38
|
{
|
|
38
|
-
'ping' =>
|
|
39
|
-
'wait' =>
|
|
40
|
-
'keys' =>
|
|
41
|
-
'dbsize' =>
|
|
42
|
-
'scan' =>
|
|
43
|
-
'lastsave' =>
|
|
44
|
-
'role' =>
|
|
45
|
-
'config' =>
|
|
46
|
-
'client' =>
|
|
47
|
-
'cluster' =>
|
|
48
|
-
'memory' =>
|
|
49
|
-
'script' =>
|
|
50
|
-
'pubsub' =>
|
|
51
|
-
'watch' =>
|
|
39
|
+
'ping' => RoutingAction.new(method_name: :send_ping_command, reply_transformer: PICK_FIRST),
|
|
40
|
+
'wait' => RoutingAction.new(method_name: :send_wait_command),
|
|
41
|
+
'keys' => RoutingAction.new(method_name: :send_command_to_replicas, reply_transformer: FLATTEN_STRINGS),
|
|
42
|
+
'dbsize' => RoutingAction.new(method_name: :send_command_to_replicas, reply_transformer: SUM_NUM),
|
|
43
|
+
'scan' => RoutingAction.new(method_name: :send_scan_command),
|
|
44
|
+
'lastsave' => RoutingAction.new(method_name: :send_command_to_all_nodes, reply_transformer: SORT_NUMBERS),
|
|
45
|
+
'role' => RoutingAction.new(method_name: :send_command_to_all_nodes),
|
|
46
|
+
'config' => RoutingAction.new(method_name: :send_config_command),
|
|
47
|
+
'client' => RoutingAction.new(method_name: :send_client_command),
|
|
48
|
+
'cluster' => RoutingAction.new(method_name: :send_cluster_command),
|
|
49
|
+
'memory' => RoutingAction.new(method_name: :send_memory_command),
|
|
50
|
+
'script' => RoutingAction.new(method_name: :send_script_command),
|
|
51
|
+
'pubsub' => RoutingAction.new(method_name: :send_pubsub_command),
|
|
52
|
+
'watch' => RoutingAction.new(method_name: :send_watch_command),
|
|
52
53
|
'mget' => multiple_key_action,
|
|
53
54
|
'mset' => multiple_key_action,
|
|
54
55
|
'del' => multiple_key_action,
|
|
@@ -61,6 +62,10 @@ class RedisClient
|
|
|
61
62
|
'select' => all_node_first_action,
|
|
62
63
|
'flushall' => primary_first_action,
|
|
63
64
|
'flushdb' => primary_first_action,
|
|
65
|
+
# The redis 7.0 tags RANDOMKEY with `request_policy:all_shards` but without any response policy.
|
|
66
|
+
# It was corrected to `response_policy:special` in the redis 7.2.
|
|
67
|
+
# This entry keeps the historical single node routing for the redis 7.0.
|
|
68
|
+
'randomkey' => single_node_action,
|
|
64
69
|
'readonly' => not_supported_action,
|
|
65
70
|
'readwrite' => not_supported_action,
|
|
66
71
|
'shutdown' => not_supported_action,
|
|
@@ -74,7 +79,33 @@ class RedisClient
|
|
|
74
79
|
end
|
|
75
80
|
end.call.freeze
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
# The routing which the command tips of the COMMAND command reply instruct.
|
|
83
|
+
# The `multi_shard` and the `special` request policies are out of scope.
|
|
84
|
+
# The `special` response policy is also out of scope because the aggregation is undefined,
|
|
85
|
+
# and the fan-out would change the return value of commands such as INFO.
|
|
86
|
+
# The `agg_min`, `agg_max` and `agg_logical_*` response policies are out of scope too:
|
|
87
|
+
# the only reachable command with them today is WAITAOF, whose reply is an array,
|
|
88
|
+
# and the aggregation of array replies is undefined. Such a command falls back to
|
|
89
|
+
# the single node routing until a command with a settled semantics appears.
|
|
90
|
+
# The entries of the DEDICATED_ACTIONS take precedence over these to keep the existing behavior.
|
|
91
|
+
# @see https://redis.io/docs/latest/develop/reference/command-tips/
|
|
92
|
+
POLICY_ACTIONS = {
|
|
93
|
+
'all_shards' => {
|
|
94
|
+
nil => RoutingAction.new(method_name: :send_command_to_primaries).freeze,
|
|
95
|
+
'all_succeeded' => RoutingAction.new(method_name: :send_command_to_primaries, reply_transformer: PICK_FIRST).freeze,
|
|
96
|
+
'one_succeeded' => RoutingAction.new(method_name: :send_command_to_primaries_leniently, reply_transformer: PICK_FIRST).freeze,
|
|
97
|
+
'agg_sum' => RoutingAction.new(method_name: :send_command_to_primaries, reply_transformer: SUM_NUM).freeze
|
|
98
|
+
}.freeze,
|
|
99
|
+
'all_nodes' => {
|
|
100
|
+
nil => RoutingAction.new(method_name: :send_command_to_all_nodes).freeze,
|
|
101
|
+
'all_succeeded' => RoutingAction.new(method_name: :send_command_to_all_nodes, reply_transformer: PICK_FIRST).freeze,
|
|
102
|
+
'one_succeeded' => RoutingAction.new(method_name: :send_command_to_all_nodes_leniently, reply_transformer: PICK_FIRST).freeze,
|
|
103
|
+
'agg_sum' => RoutingAction.new(method_name: :send_command_to_all_nodes, reply_transformer: SUM_NUM).freeze
|
|
104
|
+
}.freeze
|
|
105
|
+
}.freeze
|
|
106
|
+
|
|
107
|
+
private_constant :ZERO_CURSOR_FOR_SCAN, :TSF, :RoutingAction, :PICK_FIRST, :FLATTEN_STRINGS,
|
|
108
|
+
:SUM_NUM, :SORT_NUMBERS, :DEDICATED_ACTIONS, :POLICY_ACTIONS
|
|
78
109
|
|
|
79
110
|
attr_reader :config
|
|
80
111
|
|
|
@@ -94,7 +125,12 @@ class RedisClient
|
|
|
94
125
|
|
|
95
126
|
def send_command(method, command, *args, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
96
127
|
action = DEDICATED_ACTIONS[command.first]
|
|
97
|
-
|
|
128
|
+
if action.nil?
|
|
129
|
+
cmd_spec = @command.get_spec(command)
|
|
130
|
+
action = find_policy_action(cmd_spec)
|
|
131
|
+
return assign_node_and_send_command(method, command, args, cmd_spec: cmd_spec, &block) if action.nil?
|
|
132
|
+
end
|
|
133
|
+
|
|
98
134
|
return send(action.method_name, method, command, args, &block) if action.reply_transformer.nil?
|
|
99
135
|
|
|
100
136
|
reply = send(action.method_name, method, command, args)
|
|
@@ -124,8 +160,8 @@ class RedisClient
|
|
|
124
160
|
end
|
|
125
161
|
|
|
126
162
|
# @see https://redis.io/docs/reference/cluster-spec/#redirection-and-resharding Redirection and resharding
|
|
127
|
-
def assign_node_and_send_command(method, command, args, retry_count: 3, &block)
|
|
128
|
-
node = assign_node(command)
|
|
163
|
+
def assign_node_and_send_command(method, command, args, retry_count: 3, cmd_spec: nil, &block)
|
|
164
|
+
node = assign_node(command, cmd_spec: cmd_spec)
|
|
129
165
|
send_command_to_node(node, method, command, args, retry_count: retry_count, &block)
|
|
130
166
|
end
|
|
131
167
|
|
|
@@ -218,9 +254,9 @@ class RedisClient
|
|
|
218
254
|
end
|
|
219
255
|
end
|
|
220
256
|
|
|
221
|
-
def assign_node(command)
|
|
257
|
+
def assign_node(command, cmd_spec: nil)
|
|
222
258
|
handle_node_reload_error do
|
|
223
|
-
node_key = find_node_key(command)
|
|
259
|
+
node_key = find_node_key(command, cmd_spec: cmd_spec)
|
|
224
260
|
@node.find_by(node_key)
|
|
225
261
|
end
|
|
226
262
|
end
|
|
@@ -246,8 +282,8 @@ class RedisClient
|
|
|
246
282
|
end
|
|
247
283
|
end
|
|
248
284
|
|
|
249
|
-
def find_node_key(command, seed: nil)
|
|
250
|
-
cmd_spec = @command.get_spec(command.
|
|
285
|
+
def find_node_key(command, seed: nil, cmd_spec: nil)
|
|
286
|
+
cmd_spec = @command.get_spec(command) if cmd_spec.nil?
|
|
251
287
|
find_node_key_by_key(
|
|
252
288
|
cmd_spec&.extract_first_key(command),
|
|
253
289
|
seed: seed,
|
|
@@ -256,14 +292,14 @@ class RedisClient
|
|
|
256
292
|
end
|
|
257
293
|
|
|
258
294
|
def find_primary_node_key(command)
|
|
259
|
-
key = @command.get_spec(command
|
|
295
|
+
key = @command.get_spec(command)&.extract_first_key(command)
|
|
260
296
|
return unless key&.size&.> 0
|
|
261
297
|
|
|
262
298
|
find_node_key_by_key(key, primary: true)
|
|
263
299
|
end
|
|
264
300
|
|
|
265
301
|
def find_slot(command)
|
|
266
|
-
find_slot_by_key(@command.get_spec(command
|
|
302
|
+
find_slot_by_key(@command.get_spec(command)&.extract_first_key(command))
|
|
267
303
|
end
|
|
268
304
|
|
|
269
305
|
def find_slot_by_key(key)
|
|
@@ -308,6 +344,15 @@ class RedisClient
|
|
|
308
344
|
|
|
309
345
|
private
|
|
310
346
|
|
|
347
|
+
def find_policy_action(cmd_spec)
|
|
348
|
+
return if cmd_spec.nil?
|
|
349
|
+
|
|
350
|
+
request_policy = cmd_spec.request_policy
|
|
351
|
+
return if request_policy.nil?
|
|
352
|
+
|
|
353
|
+
POLICY_ACTIONS.dig(request_policy, cmd_spec.response_policy)
|
|
354
|
+
end
|
|
355
|
+
|
|
311
356
|
def send_command_to_all_nodes(method, command, args, &block)
|
|
312
357
|
@node.call_all(method, command, args, &block)
|
|
313
358
|
end
|
|
@@ -316,6 +361,14 @@ class RedisClient
|
|
|
316
361
|
@node.call_primaries(method, command, args, &block)
|
|
317
362
|
end
|
|
318
363
|
|
|
364
|
+
def send_command_to_all_nodes_leniently(method, command, args, &block)
|
|
365
|
+
@node.call_all_leniently(method, command, args, &block)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def send_command_to_primaries_leniently(method, command, args, &block)
|
|
369
|
+
@node.call_primaries_leniently(method, command, args, &block)
|
|
370
|
+
end
|
|
371
|
+
|
|
319
372
|
def send_command_to_replicas(method, command, args, &block)
|
|
320
373
|
@node.call_replicas(method, command, args, &block)
|
|
321
374
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: redis-cluster-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.16.
|
|
4
|
+
version: 0.16.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Taishi Kasuga
|
|
@@ -74,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
75
|
version: '0'
|
|
76
76
|
requirements: []
|
|
77
|
-
rubygems_version: 4.0.
|
|
77
|
+
rubygems_version: 4.0.16
|
|
78
78
|
specification_version: 4
|
|
79
79
|
summary: Redis cluster-aware client for Ruby
|
|
80
80
|
test_files: []
|