redis-clustering 5.0.0 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a56bfd7058c6f9725eec33ece596de34d45895d73bfb88cc948d0cdb998f2a0
4
- data.tar.gz: 0d53e2862f76de964e64910c0104bf58e95b8e0621173fb39113534f319ccd37
3
+ metadata.gz: '0390ca44d9f71661f4cfb1a7f8d1a396a84e204e992cf8a5d0755af4232cb7ac'
4
+ data.tar.gz: 923cffa3fc0a5a2aaecb4d669ea685e25047c7dc70f932f3e807e6e381fc3ecb
5
5
  SHA512:
6
- metadata.gz: 75db8468905383ebc5e1df7ac2d018289ed81a140620ea95250102d1cdec988afec684d242656f12495eb6d4f3e99c3ad42589a0910b65deba84dd30a2e80b06
7
- data.tar.gz: 9c394084604571ed515d20c2309b348acfe63283db1a8118885c6d85425fc0ba840fbe4072e12a5b16c9aab6e32353d3743ddf2e5beea89cdfd38af3406934c6
6
+ metadata.gz: b4c5f9903044360cd0317a2ad75d0c41cbd8627c34da86c9cca3471ef78e0256778c15f997f0073386b8dbfa38ca906ab03b31efb3b7c190b7412a0d6bdd1987
7
+ data.tar.gz: 4e331655c8142429b1fbee72eec3c1fd26b42f5fa4e33156a0f3415151bd7bc3b9da85e604d464b4db33c2425d6a2b910718a6b6108ede5e7bc30635371ea33f
data/README.md CHANGED
@@ -39,6 +39,12 @@ If you want [the connection to be able to read from any replica](https://redis.i
39
39
  Redis::Cluster.new(nodes: nodes, replica: true)
40
40
  ```
41
41
 
42
+ Also, you can specify the `:replica_affinity` option if you want to prevent accessing cross availability zones.
43
+
44
+ ```ruby
45
+ Redis::Cluster.new(nodes: nodes, replica: true, replica_affinity: :latency)
46
+ ```
47
+
42
48
  The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
43
49
 
44
50
  ```ruby
@@ -59,13 +65,13 @@ redis.mget('{key}1', '{key}2')
59
65
  Since Redis can return FQDN of nodes in reply to client since `7.*` with CLUSTER commands, we can use cluster feature with SSL/TLS connection like this:
60
66
 
61
67
  ```ruby
62
- Redis.new(cluster: %w[rediss://foo.example.com:6379])
68
+ Redis::Cluster.new(nodes: %w[rediss://foo.example.com:6379])
63
69
  ```
64
70
 
65
71
  On the other hand, in Redis versions prior to `6.*`, you can specify options like the following if cluster mode is enabled and client has to connect to nodes via single endpoint with SSL/TLS.
66
72
 
67
73
  ```ruby
68
- Redis.new(cluster: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
74
+ Redis::Cluster.new(nodes: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
69
75
  ```
70
76
 
71
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.
@@ -9,8 +9,10 @@ class Redis
9
9
  RedisClient::Cluster::InitialSetupError => Redis::Cluster::InitialSetupError,
10
10
  RedisClient::Cluster::OrchestrationCommandNotSupported => Redis::Cluster::OrchestrationCommandNotSupported,
11
11
  RedisClient::Cluster::AmbiguousNodeError => Redis::Cluster::AmbiguousNodeError,
12
- RedisClient::Cluster::ErrorCollection => Redis::Cluster::CommandErrorCollection
13
- ).freeze
12
+ RedisClient::Cluster::ErrorCollection => Redis::Cluster::CommandErrorCollection,
13
+ RedisClient::Cluster::Transaction::ConsistencyError => Redis::Cluster::TransactionConsistencyError,
14
+ RedisClient::Cluster::NodeMightBeDown => Redis::Cluster::NodeMightBeDown,
15
+ )
14
16
 
15
17
  class << self
16
18
  def config(**kwargs)
@@ -20,21 +22,42 @@ class Redis
20
22
  def sentinel(**kwargs)
21
23
  super(protocol: 2, **kwargs)
22
24
  end
25
+
26
+ def translate_error!(error, mapping: ERROR_MAPPING)
27
+ case error
28
+ when RedisClient::Cluster::ErrorCollection
29
+ error.errors.each do |_node, node_error|
30
+ if node_error.is_a?(RedisClient::AuthenticationError)
31
+ raise mapping.fetch(node_error.class), node_error.message, node_error.backtrace
32
+ end
33
+ end
34
+
35
+ remapped_node_errors = error.errors.map do |node_key, node_error|
36
+ remapped = mapping.fetch(node_error.class, node_error.class).new(node_error.message)
37
+ remapped.set_backtrace node_error.backtrace
38
+ [node_key, remapped]
39
+ end.to_h
40
+
41
+ raise(Redis::Cluster::CommandErrorCollection.new(remapped_node_errors, error.message).tap do |remapped|
42
+ remapped.set_backtrace error.backtrace
43
+ end)
44
+ else
45
+ Redis::Client.translate_error!(error, mapping: mapping)
46
+ end
47
+ end
23
48
  end
24
49
 
25
50
  def initialize(*)
26
51
  handle_errors { super }
27
- @inherit_socket = false
28
- @pid = Process.pid
29
52
  end
30
53
  ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
31
54
 
32
55
  def id
33
- @router.node.node_keys.join(' ')
56
+ @router.node_keys.join(' ')
34
57
  end
35
58
 
36
59
  def server_url
37
- @router.node.node_keys
60
+ @router.node_keys
38
61
  end
39
62
 
40
63
  def connected?
@@ -67,27 +90,20 @@ class Redis
67
90
  handle_errors { super(timeout, command, &block) }
68
91
  end
69
92
 
70
- def pipelined(&block)
71
- handle_errors { super(&block) }
93
+ def pipelined(exception: true, &block)
94
+ handle_errors { super(exception: exception, &block) }
72
95
  end
73
96
 
74
- def multi(&block)
75
- handle_errors { super(&block) }
97
+ def multi(watch: nil, &block)
98
+ handle_errors { super(watch: watch, &block) }
76
99
  end
77
100
 
78
101
  private
79
102
 
80
103
  def handle_errors
81
104
  yield
82
- rescue RedisClient::Cluster::ErrorCollection => error
83
- error.errors.each do |_node, node_error|
84
- if node_error.is_a?(RedisClient::AuthenticationError)
85
- raise ERROR_MAPPING.fetch(node_error.class), node_error.message, node_error.backtrace
86
- end
87
- end
88
- raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
89
105
  rescue ::RedisClient::Error => error
90
- raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
106
+ Redis::Cluster::Client.translate_error!(error)
91
107
  end
92
108
  end
93
109
  end
data/lib/redis/cluster.rb CHANGED
@@ -38,6 +38,12 @@ class Redis
38
38
  class AmbiguousNodeError < BaseError
39
39
  end
40
40
 
41
+ class TransactionConsistencyError < BaseError
42
+ end
43
+
44
+ class NodeMightBeDown < BaseError
45
+ end
46
+
41
47
  def connection
42
48
  raise NotImplementedError, "Redis::Cluster doesn't implement #connection"
43
49
  end
@@ -53,6 +59,7 @@ class Redis
53
59
  # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
54
60
  # @option options [Array<String, Hash{Symbol => String, Integer}>] :nodes List of cluster nodes to contact
55
61
  # @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
62
+ # @option options [Symbol] :replica_affinity scale reading strategy, currently supported: `:random`, `:latency`
56
63
  # @option options [String] :fixed_hostname Specify a FQDN if cluster mode enabled and
57
64
  # client has to connect nodes via single endpoint with SSL/TLS
58
65
  # @option options [Class] :connector Class of custom connector
@@ -89,6 +96,10 @@ class Redis
89
96
  send_command([:cluster, subcommand] + args, &block)
90
97
  end
91
98
 
99
+ def watch(*keys, &block)
100
+ synchronize { |c| c.call_v([:watch] + keys, &block) }
101
+ end
102
+
92
103
  private
93
104
 
94
105
  def initialize_client(options)
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.0.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -16,7 +16,7 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2022-08-29 00:00:00.000000000 Z
19
+ date: 2024-04-15 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: redis
@@ -24,28 +24,28 @@ dependencies:
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 5.0.0
27
+ version: 5.2.0
28
28
  type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 5.0.0
34
+ version: 5.2.0
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: redis-cluster-client
37
37
  requirement: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '0.2'
41
+ version: 0.7.11
42
42
  type: :runtime
43
43
  prerelease: false
44
44
  version_requirements: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '0.2'
48
+ version: 0.7.11
49
49
  description: |2
50
50
  A Ruby client that tries to match Redis' Cluster API one-to-one, while still
51
51
  providing an idiomatic interface.
@@ -68,9 +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.0.0
71
+ documentation_uri: https://www.rubydoc.info/gems/redis/5.2.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.0.0/cluster
73
+ source_code_uri: https://github.com/redis/redis-rb/tree/v5.2.0/cluster
74
74
  post_install_message:
75
75
  rdoc_options: []
76
76
  require_paths:
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  requirements: []
89
- rubygems_version: 3.1.2
89
+ rubygems_version: 3.5.3
90
90
  signing_key:
91
91
  specification_version: 4
92
92
  summary: A Ruby client library for Redis Cluster