redis-cluster-client 0.7.11 → 0.8.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b27b124d30b25712726c2d6471fffe4fd879de2dabb2002d0654e40b1e24b90e
|
4
|
+
data.tar.gz: eae0cd4ff3d6ab6317f7fff7493df1da9fb4386b4fbd187619d41e0bdf891d56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a353a42631431794e3d1d9616810ef5378930765683013cb96c8e49c010434e2f3f08995b0e48601492791b577612a9bf688dd0b186b72b0bba54e0330f24e8f
|
7
|
+
data.tar.gz: f87fed71fda0b9cf9ab3dde1b402f8c4b0c921c85efe8d794ef9fee7a48d143f43b829e6f2cd6ca01532f0c8c6ca8f682195ea3673aefc9ba5d342a9871a6c75
|
@@ -8,26 +8,56 @@ class RedisClient
|
|
8
8
|
class OptimisticLocking
|
9
9
|
def initialize(router)
|
10
10
|
@router = router
|
11
|
+
@asking = false
|
11
12
|
end
|
12
13
|
|
13
14
|
def watch(keys)
|
14
15
|
slot = find_slot(keys)
|
15
16
|
raise ::RedisClient::Cluster::Transaction::ConsistencyError, "unsafe watch: #{keys.join(' ')}" if slot.nil?
|
16
17
|
|
18
|
+
# We have not yet selected a node for this transaction, initially, which means we can handle
|
19
|
+
# redirections freely initially (i.e. for the first WATCH call)
|
17
20
|
node = @router.find_primary_node_by_slot(slot)
|
18
|
-
|
21
|
+
handle_redirection(node, retry_count: 1) do |nd|
|
19
22
|
nd.with do |c|
|
20
|
-
c.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
c.ensure_connected_cluster_scoped(retryable: false) do
|
24
|
+
c.call('ASKING') if @asking
|
25
|
+
c.call('WATCH', *keys)
|
26
|
+
begin
|
27
|
+
yield(c, slot, @asking)
|
28
|
+
rescue ::RedisClient::ConnectionError
|
29
|
+
# No need to unwatch on a connection error.
|
30
|
+
raise
|
31
|
+
rescue StandardError
|
32
|
+
c.call('UNWATCH')
|
33
|
+
raise
|
34
|
+
end
|
35
|
+
end
|
25
36
|
end
|
26
37
|
end
|
27
38
|
end
|
28
39
|
|
29
40
|
private
|
30
41
|
|
42
|
+
def handle_redirection(node, retry_count: 1, &blk)
|
43
|
+
@router.handle_redirection(node, retry_count: retry_count) do |nd|
|
44
|
+
handle_asking_once(nd, &blk)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_asking_once(node)
|
49
|
+
yield node
|
50
|
+
rescue ::RedisClient::CommandError => e
|
51
|
+
raise unless ErrorIdentification.client_owns_error?(e, node)
|
52
|
+
raise unless e.message.start_with?('ASK')
|
53
|
+
|
54
|
+
node = @router.assign_asking_node(e.message)
|
55
|
+
@asking = true
|
56
|
+
yield node
|
57
|
+
ensure
|
58
|
+
@asking = false
|
59
|
+
end
|
60
|
+
|
31
61
|
def find_slot(keys)
|
32
62
|
return if keys.empty?
|
33
63
|
return if keys.any? { |k| k.nil? || k.empty? }
|
@@ -12,7 +12,7 @@ class RedisClient
|
|
12
12
|
class Extended < ::RedisClient::Pipeline
|
13
13
|
attr_reader :outer_indices
|
14
14
|
|
15
|
-
def initialize(
|
15
|
+
def initialize(...)
|
16
16
|
super
|
17
17
|
@outer_indices = nil
|
18
18
|
end
|
@@ -50,14 +50,14 @@ class RedisClient
|
|
50
50
|
end
|
51
51
|
|
52
52
|
::RedisClient::ConnectionMixin.module_eval do
|
53
|
-
def call_pipelined_aware_of_redirection(commands, timeouts) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
53
|
+
def call_pipelined_aware_of_redirection(commands, timeouts, exception:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
54
54
|
size = commands.size
|
55
55
|
results = Array.new(commands.size)
|
56
56
|
@pending_reads += size
|
57
57
|
write_multi(commands)
|
58
58
|
|
59
59
|
redirection_indices = nil
|
60
|
-
|
60
|
+
first_exception = nil
|
61
61
|
size.times do |index|
|
62
62
|
timeout = timeouts && timeouts[index]
|
63
63
|
result = read(timeout)
|
@@ -67,14 +67,14 @@ class RedisClient
|
|
67
67
|
if result.is_a?(::RedisClient::CommandError) && result.message.start_with?('MOVED', 'ASK')
|
68
68
|
redirection_indices ||= []
|
69
69
|
redirection_indices << index
|
70
|
-
|
71
|
-
|
70
|
+
elsif exception
|
71
|
+
first_exception ||= result
|
72
72
|
end
|
73
73
|
end
|
74
74
|
results[index] = result
|
75
75
|
end
|
76
76
|
|
77
|
-
raise
|
77
|
+
raise first_exception if exception && first_exception
|
78
78
|
return results if redirection_indices.nil?
|
79
79
|
|
80
80
|
err = ::RedisClient::Cluster::Pipeline::RedirectionNeeded.new
|
@@ -98,10 +98,11 @@ class RedisClient
|
|
98
98
|
attr_accessor :replies, :indices
|
99
99
|
end
|
100
100
|
|
101
|
-
def initialize(router, command_builder, concurrent_worker, seed: Random.new_seed)
|
101
|
+
def initialize(router, command_builder, concurrent_worker, exception:, seed: Random.new_seed)
|
102
102
|
@router = router
|
103
103
|
@command_builder = command_builder
|
104
104
|
@concurrent_worker = concurrent_worker
|
105
|
+
@exception = exception
|
105
106
|
@seed = seed
|
106
107
|
@pipelines = nil
|
107
108
|
@size = 0
|
@@ -212,7 +213,7 @@ class RedisClient
|
|
212
213
|
results = client.ensure_connected_cluster_scoped(retryable: pipeline._retryable?) do |connection|
|
213
214
|
commands = pipeline._commands
|
214
215
|
client.middlewares.call_pipelined(commands, client.config) do
|
215
|
-
connection.call_pipelined_aware_of_redirection(commands, pipeline._timeouts)
|
216
|
+
connection.call_pipelined_aware_of_redirection(commands, pipeline._timeouts, exception: @exception)
|
216
217
|
end
|
217
218
|
end
|
218
219
|
|
@@ -224,15 +225,21 @@ class RedisClient
|
|
224
225
|
|
225
226
|
if err.message.start_with?('MOVED')
|
226
227
|
node = @router.assign_redirection_node(err.message)
|
227
|
-
|
228
|
+
try_redirection(node, pipeline, inner_index)
|
228
229
|
elsif err.message.start_with?('ASK')
|
229
230
|
node = @router.assign_asking_node(err.message)
|
230
|
-
try_asking(node) ?
|
231
|
+
try_asking(node) ? try_redirection(node, pipeline, inner_index) : err
|
231
232
|
else
|
232
233
|
err
|
233
234
|
end
|
234
235
|
end
|
235
236
|
|
237
|
+
def try_redirection(node, pipeline, inner_index)
|
238
|
+
redirect_command(node, pipeline, inner_index)
|
239
|
+
rescue StandardError => e
|
240
|
+
@exception ? raise : e
|
241
|
+
end
|
242
|
+
|
236
243
|
def redirect_command(node, pipeline, inner_index)
|
237
244
|
method = pipeline.get_callee_method(inner_index)
|
238
245
|
command = pipeline.get_command(inner_index)
|
@@ -315,9 +315,9 @@ class RedisClient
|
|
315
315
|
def send_watch_command(command)
|
316
316
|
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?
|
317
317
|
|
318
|
-
::RedisClient::Cluster::OptimisticLocking.new(self).watch(command[1..]) do |c, slot|
|
318
|
+
::RedisClient::Cluster::OptimisticLocking.new(self).watch(command[1..]) do |c, slot, asking|
|
319
319
|
transaction = ::RedisClient::Cluster::Transaction.new(
|
320
|
-
self, @command_builder, node: c, slot: slot
|
320
|
+
self, @command_builder, node: c, slot: slot, asking: asking
|
321
321
|
)
|
322
322
|
yield transaction
|
323
323
|
transaction.execute
|
@@ -9,7 +9,7 @@ class RedisClient
|
|
9
9
|
ConsistencyError = Class.new(::RedisClient::Error)
|
10
10
|
MAX_REDIRECTION = 2
|
11
11
|
|
12
|
-
def initialize(router, command_builder, node: nil, slot: nil)
|
12
|
+
def initialize(router, command_builder, node: nil, slot: nil, asking: false)
|
13
13
|
@router = router
|
14
14
|
@command_builder = command_builder
|
15
15
|
@retryable = true
|
@@ -18,6 +18,7 @@ class RedisClient
|
|
18
18
|
@node = node
|
19
19
|
prepare_tx unless @node.nil?
|
20
20
|
@watching_slot = slot
|
21
|
+
@asking = asking
|
21
22
|
end
|
22
23
|
|
23
24
|
def call(*command, **kwargs, &block)
|
@@ -93,7 +94,11 @@ class RedisClient
|
|
93
94
|
|
94
95
|
def settle
|
95
96
|
@pipeline.call('EXEC')
|
96
|
-
|
97
|
+
# If we needed ASKING on the watch, we need ASKING on the multi as well.
|
98
|
+
@node.call('ASKING') if @asking
|
99
|
+
# Don't handle redirections at this level if we're in a watch (the watcher handles redirections
|
100
|
+
# at the whole-transaction level.)
|
101
|
+
send_transaction(@node, redirect: !!@watching_slot ? 0 : MAX_REDIRECTION)
|
97
102
|
end
|
98
103
|
|
99
104
|
def send_transaction(client, redirect:)
|
@@ -110,7 +115,8 @@ class RedisClient
|
|
110
115
|
client.middlewares.call_pipelined(commands, client.config) do
|
111
116
|
connection.call_pipelined(commands, nil)
|
112
117
|
rescue ::RedisClient::CommandError => e
|
113
|
-
|
118
|
+
ensure_the_same_slot!(commands)
|
119
|
+
return handle_command_error!(e, redirect: redirect) unless redirect.zero?
|
114
120
|
|
115
121
|
raise
|
116
122
|
end
|
@@ -139,15 +145,13 @@ class RedisClient
|
|
139
145
|
results
|
140
146
|
end
|
141
147
|
|
142
|
-
def handle_command_error!(
|
148
|
+
def handle_command_error!(err, redirect:) # rubocop:disable Metrics/AbcSize
|
143
149
|
if err.message.start_with?('CROSSSLOT')
|
144
150
|
raise ConsistencyError, "#{err.message}: #{err.command}"
|
145
151
|
elsif err.message.start_with?('MOVED')
|
146
|
-
ensure_the_same_slot!(commands)
|
147
152
|
node = @router.assign_redirection_node(err.message)
|
148
153
|
send_transaction(node, redirect: redirect - 1)
|
149
154
|
elsif err.message.start_with?('ASK')
|
150
|
-
ensure_the_same_slot!(commands)
|
151
155
|
node = @router.assign_asking_node(err.message)
|
152
156
|
try_asking(node) ? send_transaction(node, redirect: redirect - 1) : err
|
153
157
|
else
|
data/lib/redis_client/cluster.rb
CHANGED
@@ -82,9 +82,16 @@ class RedisClient
|
|
82
82
|
@router.try_delegate(node, :zscan, key, *args, **kwargs, &block)
|
83
83
|
end
|
84
84
|
|
85
|
-
def pipelined
|
85
|
+
def pipelined(exception: true)
|
86
86
|
seed = @config.use_replica? && @config.replica_affinity == :random ? nil : Random.new_seed
|
87
|
-
pipeline = ::RedisClient::Cluster::Pipeline.new(
|
87
|
+
pipeline = ::RedisClient::Cluster::Pipeline.new(
|
88
|
+
@router,
|
89
|
+
@command_builder,
|
90
|
+
@concurrent_worker,
|
91
|
+
exception: exception,
|
92
|
+
seed: seed
|
93
|
+
)
|
94
|
+
|
88
95
|
yield pipeline
|
89
96
|
return [] if pipeline.empty?
|
90
97
|
|
@@ -98,9 +105,9 @@ class RedisClient
|
|
98
105
|
return transaction.execute
|
99
106
|
end
|
100
107
|
|
101
|
-
::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, slot|
|
108
|
+
::RedisClient::Cluster::OptimisticLocking.new(@router).watch(watch) do |c, slot, asking|
|
102
109
|
transaction = ::RedisClient::Cluster::Transaction.new(
|
103
|
-
@router, @command_builder, node: c, slot: slot
|
110
|
+
@router, @command_builder, node: c, slot: slot, asking: asking
|
104
111
|
)
|
105
112
|
yield transaction
|
106
113
|
transaction.execute
|
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.8.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-
|
11
|
+
date: 2024-04-12 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.22'
|
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.22'
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- proxy0721@gmail.com
|