redis-clustering 5.2.0 → 5.4.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/README.md +31 -0
- data/lib/redis/cluster/client.rb +31 -2
- data/lib/redis/cluster/transaction_adapter.rb +104 -0
- data/lib/redis/cluster.rb +26 -1
- metadata +10 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7060eff856ef3d21ddeff60bfd2a0b6d741d04fd9b233f5b36eee50812b88bc
|
4
|
+
data.tar.gz: 07d96f3179db08a80f054542474ef0d69a3db1cfce92b80b729a9f2b04bf9e1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05b728ef68b71a9dc1f370cb2c03cc5fb7bc01c9a3278b160cebf0f6de3a6b42ad5cb3c9c9a30e9a49f9f4cffad16ec926825796941e2d0d99b09fad964a0773
|
7
|
+
data.tar.gz: 6b16c0354a7a8bfbef6124186e98d28e183e00e614471543e51acfca01585a44a35f1157b75b815c6bb156ca4be975c39c1eb4ce9d0aa248db4834040023d77c
|
data/README.md
CHANGED
@@ -75,3 +75,34 @@ Redis::Cluster.new(nodes: %w[rediss://foo-endpoint.example.com:6379], fixed_host
|
|
75
75
|
```
|
76
76
|
|
77
77
|
In case of the above architecture, if you don't pass the `fixed_hostname` option to the client and servers return IP addresses of nodes, the client may fail to verify certificates.
|
78
|
+
|
79
|
+
## Transaction with an optimistic locking
|
80
|
+
Since Redis cluster is a distributed system, several behaviors are different from a standalone server.
|
81
|
+
Client libraries can make them compatible up to a point, but a part of features needs some restrictions.
|
82
|
+
Especially, some cautions are needed to use the transaction feature with an optimistic locking.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# The client is an instance of the internal adapter for the optimistic locking
|
86
|
+
redis.watch("{my}key") do |client|
|
87
|
+
if client.get("{my}key") == "some value"
|
88
|
+
# The tx is an instance of the internal adapter for the transaction
|
89
|
+
client.multi do |tx|
|
90
|
+
tx.set("{my}key", "other value")
|
91
|
+
tx.incr("{my}counter")
|
92
|
+
end
|
93
|
+
else
|
94
|
+
client.unwatch
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
In a cluster mode client, you need to pass a block if you call the watch method and you need to specify an argument to the block.
|
100
|
+
Also, you should use the block argument as a receiver to call commands in the block.
|
101
|
+
Although the above restrictions are needed, this implementations is compatible with a standalone client.
|
102
|
+
|
103
|
+
## MGET, MSET and DEL
|
104
|
+
This gem allows you to use MGET, MSET and DEL specifying multiple keys without a hash tag.
|
105
|
+
Cross-slot errors are prevented by an internal dedicated implementation.
|
106
|
+
The underlying library makes the behavior possible.
|
107
|
+
(ref. [redis-cluster-client](https://github.com/redis-rb/redis-cluster-client))
|
108
|
+
That said, we recommend to use a hash tag for these commands to the better performance.
|
data/lib/redis/cluster/client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'redis-cluster-client'
|
4
|
+
require 'redis/cluster/transaction_adapter'
|
4
5
|
|
5
6
|
class Redis
|
6
7
|
class Cluster
|
@@ -53,11 +54,11 @@ class Redis
|
|
53
54
|
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
|
54
55
|
|
55
56
|
def id
|
56
|
-
|
57
|
+
server_url.join(' ')
|
57
58
|
end
|
58
59
|
|
59
60
|
def server_url
|
60
|
-
@router.node_keys
|
61
|
+
@router.nil? ? @config.startup_nodes.keys : router.node_keys
|
61
62
|
end
|
62
63
|
|
63
64
|
def connected?
|
@@ -98,6 +99,34 @@ class Redis
|
|
98
99
|
handle_errors { super(watch: watch, &block) }
|
99
100
|
end
|
100
101
|
|
102
|
+
def watch(*keys, &block)
|
103
|
+
unless block_given?
|
104
|
+
raise(
|
105
|
+
Redis::Cluster::TransactionConsistencyError,
|
106
|
+
'A block is required if you use the cluster client.'
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
unless block.arity == 1
|
111
|
+
raise(
|
112
|
+
Redis::Cluster::TransactionConsistencyError,
|
113
|
+
'Given block needs an argument if you use the cluster client.'
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
handle_errors do
|
118
|
+
RedisClient::Cluster::OptimisticLocking.new(router).watch(keys) do |c, slot, asking|
|
119
|
+
transaction = Redis::Cluster::TransactionAdapter.new(
|
120
|
+
self, router, @command_builder, node: c, slot: slot, asking: asking
|
121
|
+
)
|
122
|
+
|
123
|
+
result = yield transaction
|
124
|
+
c.call('UNWATCH') unless transaction.lock_released?
|
125
|
+
result
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
101
130
|
private
|
102
131
|
|
103
132
|
def handle_errors
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'redis_client/cluster/transaction'
|
4
|
+
|
5
|
+
class Redis
|
6
|
+
class Cluster
|
7
|
+
class TransactionAdapter
|
8
|
+
class Internal < RedisClient::Cluster::Transaction
|
9
|
+
def initialize(client, router, command_builder, node: nil, slot: nil, asking: false)
|
10
|
+
@client = client
|
11
|
+
super(router, command_builder, node: node, slot: slot, asking: asking)
|
12
|
+
end
|
13
|
+
|
14
|
+
def multi
|
15
|
+
raise(Redis::Cluster::TransactionConsistencyError, "Can't nest multi transaction")
|
16
|
+
end
|
17
|
+
|
18
|
+
def exec
|
19
|
+
# no need to do anything
|
20
|
+
end
|
21
|
+
|
22
|
+
def discard
|
23
|
+
# no need to do anything
|
24
|
+
end
|
25
|
+
|
26
|
+
def watch(*_)
|
27
|
+
raise(Redis::Cluster::TransactionConsistencyError, "Can't use watch in a transaction")
|
28
|
+
end
|
29
|
+
|
30
|
+
def unwatch
|
31
|
+
# no need to do anything
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def method_missing(name, *args, **kwargs, &block)
|
37
|
+
return call(name, *args, **kwargs, &block) if @client.respond_to?(name)
|
38
|
+
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def respond_to_missing?(name, include_private = false)
|
43
|
+
return true if @client.respond_to?(name)
|
44
|
+
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(client, router, command_builder, node: nil, slot: nil, asking: false)
|
50
|
+
@client = client
|
51
|
+
@router = router
|
52
|
+
@command_builder = command_builder
|
53
|
+
@node = node
|
54
|
+
@slot = slot
|
55
|
+
@asking = asking
|
56
|
+
@lock_released = false
|
57
|
+
end
|
58
|
+
|
59
|
+
def lock_released?
|
60
|
+
@lock_released
|
61
|
+
end
|
62
|
+
|
63
|
+
def multi
|
64
|
+
@lock_released = true
|
65
|
+
transaction = Redis::Cluster::TransactionAdapter::Internal.new(
|
66
|
+
@client, @router, @command_builder, node: @node, slot: @slot, asking: @asking
|
67
|
+
)
|
68
|
+
yield transaction
|
69
|
+
transaction.execute
|
70
|
+
end
|
71
|
+
|
72
|
+
def exec
|
73
|
+
# no need to do anything
|
74
|
+
end
|
75
|
+
|
76
|
+
def discard
|
77
|
+
# no need to do anything
|
78
|
+
end
|
79
|
+
|
80
|
+
def watch(*_)
|
81
|
+
raise(Redis::Cluster::TransactionConsistencyError, "Can't nest watch command if you use the cluster client")
|
82
|
+
end
|
83
|
+
|
84
|
+
def unwatch
|
85
|
+
@lock_released = true
|
86
|
+
@node.call('UNWATCH')
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def method_missing(name, *args, **kwargs, &block)
|
92
|
+
return @client.public_send(name, *args, **kwargs, &block) if @client.respond_to?(name)
|
93
|
+
|
94
|
+
super
|
95
|
+
end
|
96
|
+
|
97
|
+
def respond_to_missing?(name, include_private = false)
|
98
|
+
return true if @client.respond_to?(name)
|
99
|
+
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/redis/cluster.rb
CHANGED
@@ -96,8 +96,33 @@ class Redis
|
|
96
96
|
send_command([:cluster, subcommand] + args, &block)
|
97
97
|
end
|
98
98
|
|
99
|
+
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
100
|
+
#
|
101
|
+
# Using a block is required for a cluster client. It's different from a standalone client.
|
102
|
+
# And you should use the block argument as a receiver if you call commands.
|
103
|
+
#
|
104
|
+
# An `#unwatch` is automatically issued if an exception is raised within the
|
105
|
+
# block that is a subclass of StandardError and is not a ConnectionError.
|
106
|
+
#
|
107
|
+
# @param keys [String, Array<String>] one or more keys to watch
|
108
|
+
# @return [Object] returns the return value of the block
|
109
|
+
#
|
110
|
+
# @example A typical use case.
|
111
|
+
# # The client is an instance of the internal adapter for the optimistic locking
|
112
|
+
# redis.watch("{my}key") do |client|
|
113
|
+
# if client.get("{my}key") == "some value"
|
114
|
+
# # The tx is an instance of the internal adapter for the transaction
|
115
|
+
# client.multi do |tx|
|
116
|
+
# tx.set("{my}key", "other value")
|
117
|
+
# tx.incr("{my}counter")
|
118
|
+
# end
|
119
|
+
# else
|
120
|
+
# client.unwatch
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
# #=> ["OK", 6]
|
99
124
|
def watch(*keys, &block)
|
100
|
-
synchronize { |c| c.
|
125
|
+
synchronize { |c| c.watch(*keys, &block) }
|
101
126
|
end
|
102
127
|
|
103
128
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-clustering
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -13,10 +13,9 @@ authors:
|
|
13
13
|
- Michel Martens
|
14
14
|
- Damian Janowski
|
15
15
|
- Pieter Noordhuis
|
16
|
-
autorequire:
|
17
16
|
bindir: bin
|
18
17
|
cert_chain: []
|
19
|
-
date:
|
18
|
+
date: 2025-02-20 00:00:00.000000000 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: redis
|
@@ -24,28 +23,28 @@ dependencies:
|
|
24
23
|
requirements:
|
25
24
|
- - '='
|
26
25
|
- !ruby/object:Gem::Version
|
27
|
-
version: 5.
|
26
|
+
version: 5.4.0
|
28
27
|
type: :runtime
|
29
28
|
prerelease: false
|
30
29
|
version_requirements: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
31
|
- - '='
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version: 5.
|
33
|
+
version: 5.4.0
|
35
34
|
- !ruby/object:Gem::Dependency
|
36
35
|
name: redis-cluster-client
|
37
36
|
requirement: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
38
|
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
40
|
+
version: 0.10.0
|
42
41
|
type: :runtime
|
43
42
|
prerelease: false
|
44
43
|
version_requirements: !ruby/object:Gem::Requirement
|
45
44
|
requirements:
|
46
45
|
- - ">="
|
47
46
|
- !ruby/object:Gem::Version
|
48
|
-
version: 0.
|
47
|
+
version: 0.10.0
|
49
48
|
description: |2
|
50
49
|
A Ruby client that tries to match Redis' Cluster API one-to-one, while still
|
51
50
|
providing an idiomatic interface.
|
@@ -61,6 +60,7 @@ files:
|
|
61
60
|
- lib/redis-clustering.rb
|
62
61
|
- lib/redis/cluster.rb
|
63
62
|
- lib/redis/cluster/client.rb
|
63
|
+
- lib/redis/cluster/transaction_adapter.rb
|
64
64
|
- lib/redis/cluster/version.rb
|
65
65
|
homepage: https://github.com/redis/redis-rb/blob/master/cluster
|
66
66
|
licenses:
|
@@ -68,10 +68,9 @@ licenses:
|
|
68
68
|
metadata:
|
69
69
|
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
70
70
|
changelog_uri: https://github.com/redis/redis-rb/blob/master/cluster/CHANGELOG.md
|
71
|
-
documentation_uri: https://www.rubydoc.info/gems/redis/5.
|
71
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/5.4.0
|
72
72
|
homepage_uri: https://github.com/redis/redis-rb/blob/master/cluster
|
73
|
-
source_code_uri: https://github.com/redis/redis-rb/tree/v5.
|
74
|
-
post_install_message:
|
73
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v5.4.0/cluster
|
75
74
|
rdoc_options: []
|
76
75
|
require_paths:
|
77
76
|
- lib
|
@@ -86,8 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
85
|
- !ruby/object:Gem::Version
|
87
86
|
version: '0'
|
88
87
|
requirements: []
|
89
|
-
rubygems_version: 3.
|
90
|
-
signing_key:
|
88
|
+
rubygems_version: 3.6.2
|
91
89
|
specification_version: 4
|
92
90
|
summary: A Ruby client library for Redis Cluster
|
93
91
|
test_files: []
|