redis-clustering 5.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a1f30a75985b5fc7e5ea4f5dfa1b8daaf85e2f0e387c669977c9602035e940cf
4
+ data.tar.gz: 316047ae9330f0fee89d4870a6bbf56a79158bd8050d5f382956bae971618398
5
+ SHA512:
6
+ metadata.gz: 9de07f2ae00e29220f13a09aad0f2741c87e4f41597385775ec4f2dcc049fc92b7a1c559b8230d5519c8f91f41d880575017c4e0f4519fb04d5ca3f16c005906
7
+ data.tar.gz: e02b002e2c7b61c6acba9fc586fbd9b3f47c1cdf6e81f8e4f40d3d366dd740994040e4d9ad642c97c3a1527ae25947d90feb61f49d9fce2424af979171504002
data/CHANGELOG.md ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Ezra Zygmuntowicz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Redis::Cluster
2
+
3
+ ## Getting started
4
+
5
+ Install with:
6
+
7
+ ```
8
+ $ gem install redis-clustering
9
+ ```
10
+
11
+ You can connect to Redis by instantiating the `Redis::Cluster` class:
12
+
13
+ ```ruby
14
+ require "redis-clustering"
15
+
16
+ redis = Redis::Cluter.new(nodes: (7000..7005).map { |port| "redis://127.0.0.1:#{port}" })
17
+ ```
18
+
19
+ NB: Both `redis_cluster` and `redis-cluster` are unrelated and abandoned gems.
20
+
21
+ ```ruby
22
+ # Nodes can be passed to the client as an array of connection URLs.
23
+ nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
24
+ redis = Redis::Cluster.new(nodes: nodes)
25
+
26
+ # You can also specify the options as a Hash. The options are the same as for a single server connection.
27
+ (7000..7005).map { |port| { host: '127.0.0.1', port: port } }
28
+ ```
29
+
30
+ You can also specify only a subset of the nodes, and the client will discover the missing ones using the [CLUSTER NODES](https://redis.io/commands/cluster-nodes) command.
31
+
32
+ ```ruby
33
+ Redis::Cluster.new(nodes: %w[redis://127.0.0.1:7000])
34
+ ```
35
+
36
+ If you want [the connection to be able to read from any replica](https://redis.io/commands/readonly), you must pass the `replica: true`. Note that this connection won't be usable to write keys.
37
+
38
+ ```ruby
39
+ Redis::Cluster.new(nodes: nodes, replica: true)
40
+ ```
41
+
42
+ The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
43
+
44
+ ```ruby
45
+ redis = Redis::Cluster.new(nodes: %w[redis://127.0.0.1:7000])
46
+
47
+ redis.mget('key1', 'key2')
48
+ #=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
49
+
50
+ redis.mget('{key}1', '{key}2')
51
+ #=> [nil, nil]
52
+ ```
53
+
54
+ * The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
55
+ * The client support permanent node failures, and will reroute requests to promoted slaves.
56
+ * The client supports `MOVED` and `ASK` redirections transparently.
57
+
58
+ ## Cluster mode with SSL/TLS
59
+ 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
+
61
+ ```ruby
62
+ Redis.new(cluster: %w[rediss://foo.example.com:6379])
63
+ ```
64
+
65
+ 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
+
67
+ ```ruby
68
+ Redis.new(cluster: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
69
+ ```
70
+
71
+ 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.
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'redis-cluster-client'
4
+
5
+ class Redis
6
+ class Cluster
7
+ class Client < RedisClient::Cluster
8
+ ERROR_MAPPING = ::Redis::Client::ERROR_MAPPING.merge(
9
+ RedisClient::Cluster::InitialSetupError => Redis::Cluster::InitialSetupError,
10
+ RedisClient::Cluster::OrchestrationCommandNotSupported => Redis::Cluster::OrchestrationCommandNotSupported,
11
+ RedisClient::Cluster::AmbiguousNodeError => Redis::Cluster::AmbiguousNodeError,
12
+ RedisClient::Cluster::ErrorCollection => Redis::Cluster::CommandErrorCollection
13
+ ).freeze
14
+
15
+ class << self
16
+ def config(**kwargs)
17
+ super(protocol: 2, **kwargs)
18
+ end
19
+
20
+ def sentinel(**kwargs)
21
+ super(protocol: 2, **kwargs)
22
+ end
23
+ end
24
+
25
+ def initialize(*)
26
+ handle_errors { super }
27
+ @inherit_socket = false
28
+ @pid = Process.pid
29
+ end
30
+ ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
31
+
32
+ def id
33
+ @router.node.node_keys.join(' ')
34
+ end
35
+
36
+ def server_url
37
+ @router.node.node_keys
38
+ end
39
+
40
+ def connected?
41
+ true
42
+ end
43
+
44
+ def disable_reconnection
45
+ yield # TODO: do we need this, is it doable?
46
+ end
47
+
48
+ def timeout
49
+ config.read_timeout
50
+ end
51
+
52
+ def db
53
+ 0
54
+ end
55
+
56
+ undef_method :call
57
+ undef_method :call_once
58
+ undef_method :call_once_v
59
+ undef_method :blocking_call
60
+
61
+ def call_v(command, &block)
62
+ handle_errors { super(command, &block) }
63
+ end
64
+
65
+ def blocking_call_v(timeout, command, &block)
66
+ timeout += self.timeout if timeout && timeout > 0
67
+ handle_errors { super(timeout, command, &block) }
68
+ end
69
+
70
+ def pipelined(&block)
71
+ handle_errors { super(&block) }
72
+ end
73
+
74
+ def multi(&block)
75
+ handle_errors { super(&block) }
76
+ end
77
+
78
+ private
79
+
80
+ def handle_errors
81
+ 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
+ rescue ::RedisClient::Error => error
90
+ raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redis/version"
4
+
5
+ class Redis
6
+ class Cluster
7
+ VERSION = Redis::VERSION
8
+ end
9
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redis"
4
+
5
+ class Redis
6
+ class Cluster < ::Redis
7
+ # Raised when client connected to redis as cluster mode
8
+ # and failed to fetch cluster state information by commands.
9
+ class InitialSetupError < BaseError
10
+ end
11
+
12
+ # Raised when client connected to redis as cluster mode
13
+ # and some cluster subcommands were called.
14
+ class OrchestrationCommandNotSupported < BaseError
15
+ def initialize(command, subcommand = '')
16
+ str = [command, subcommand].map(&:to_s).reject(&:empty?).join(' ').upcase
17
+ msg = "#{str} command should be used with care "\
18
+ 'only by applications orchestrating Redis Cluster, like redis-trib, '\
19
+ 'and the command if used out of the right context can leave the cluster '\
20
+ 'in a wrong state or cause data loss.'
21
+ super(msg)
22
+ end
23
+ end
24
+
25
+ # Raised when error occurs on any node of cluster.
26
+ class CommandErrorCollection < BaseError
27
+ attr_reader :errors
28
+
29
+ # @param errors [Hash{String => Redis::CommandError}]
30
+ # @param error_message [String]
31
+ def initialize(errors, error_message = 'Command errors were replied on any node')
32
+ @errors = errors
33
+ super(error_message)
34
+ end
35
+ end
36
+
37
+ # Raised when cluster client can't select node.
38
+ class AmbiguousNodeError < BaseError
39
+ end
40
+
41
+ def connection
42
+ raise NotImplementedError, "Redis::Cluster doesn't implement #connection"
43
+ end
44
+
45
+ # Create a new client instance
46
+ #
47
+ # @param [Hash] options
48
+ # @option options [Float] :timeout (5.0) timeout in seconds
49
+ # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
50
+ # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`
51
+ # @option options [Integer, Array<Integer, Float>] :reconnect_attempts Number of attempts trying to connect,
52
+ # or a list of sleep duration between attempts.
53
+ # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
54
+ # @option options [Array<String, Hash{Symbol => String, Integer}>] :nodes List of cluster nodes to contact
55
+ # @option options [Boolean] :replica Whether to use readonly replica nodes in Redis Cluster or not
56
+ # @option options [String] :fixed_hostname Specify a FQDN if cluster mode enabled and
57
+ # client has to connect nodes via single endpoint with SSL/TLS
58
+ # @option options [Class] :connector Class of custom connector
59
+ #
60
+ # @return [Redis::Cluster] a new client instance
61
+ def initialize(*) # rubocop:disable Lint/UselessMethodDefinition
62
+ super
63
+ end
64
+ ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
65
+
66
+ # Sends `CLUSTER *` command to random node and returns its reply.
67
+ #
68
+ # @see https://redis.io/commands#cluster Reference of cluster command
69
+ #
70
+ # @param subcommand [String, Symbol] the subcommand of cluster command
71
+ # e.g. `:slots`, `:nodes`, `:slaves`, `:info`
72
+ #
73
+ # @return [Object] depends on the subcommand
74
+ def cluster(subcommand, *args)
75
+ subcommand = subcommand.to_s.downcase
76
+ block = case subcommand
77
+ when 'slots'
78
+ HashifyClusterSlots
79
+ when 'nodes'
80
+ HashifyClusterNodes
81
+ when 'slaves'
82
+ HashifyClusterSlaves
83
+ when 'info'
84
+ HashifyInfo
85
+ else
86
+ Noop
87
+ end
88
+
89
+ send_command([:cluster, subcommand] + args, &block)
90
+ end
91
+
92
+ private
93
+
94
+ def initialize_client(options)
95
+ cluster_config = RedisClient.cluster(**options, protocol: 2, client_implementation: ::Redis::Cluster::Client)
96
+ cluster_config.new_client
97
+ end
98
+ end
99
+ end
100
+
101
+ require "redis/cluster/client"
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redis/cluster"
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-clustering
3
+ version: !ruby/object:Gem::Version
4
+ version: 5.0.0.beta3
5
+ platform: ruby
6
+ authors:
7
+ - Ezra Zygmuntowicz
8
+ - Taylor Weibley
9
+ - Matthew Clark
10
+ - Brian McKinney
11
+ - Salvatore Sanfilippo
12
+ - Luca Guidi
13
+ - Michel Martens
14
+ - Damian Janowski
15
+ - Pieter Noordhuis
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+ date: 2022-08-18 00:00:00.000000000 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: redis-cluster-client
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.2'
28
+ type: :runtime
29
+ prerelease: false
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0.2'
35
+ description: |2
36
+ A Ruby client that tries to match Redis' Cluster API one-to-one, while still
37
+ providing an idiomatic interface.
38
+ email:
39
+ - redis-db@googlegroups.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - CHANGELOG.md
45
+ - LICENSE
46
+ - README.md
47
+ - lib/redis-clustering.rb
48
+ - lib/redis/cluster.rb
49
+ - lib/redis/cluster/client.rb
50
+ - lib/redis/cluster/version.rb
51
+ homepage: https://github.com/redis/redis-rb/blob/master/cluster
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ bug_tracker_uri: https://github.com/redis/redis-rb/issues
56
+ changelog_uri: https://github.com/redis/redis-rb/blob/master/cluster/CHANGELOG.md
57
+ documentation_uri: https://www.rubydoc.info/gems/redis/5.0.0.beta3
58
+ homepage_uri: https://github.com/redis/redis-rb/blob/master/cluster
59
+ source_code_uri: https://github.com/redis/redis-rb/tree/v5.0.0.beta3/cluster
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 2.7.0
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">"
72
+ - !ruby/object:Gem::Version
73
+ version: 1.3.1
74
+ requirements: []
75
+ rubygems_version: 3.1.2
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: A Ruby client library for Redis Cluster
79
+ test_files: []