class SentinelClient
A Redis Sentinel client for high availability Redis deployments.
Definitions
def initialize(endpoints, master_name: DEFAULT_MASTER_NAME, master_options: nil, slave_options: nil, role: :master, **options)
Create a new instance of the SentinelClient.
Implementation
def initialize(endpoints, master_name: DEFAULT_MASTER_NAME, master_options: nil, slave_options: nil, role: :master, **options)
@endpoints = endpoints
@master_name = master_name
@master_options = master_options || {}
@slave_options = slave_options || @master_options
@role = role
# A cache of sentinel connections.
@sentinels = {}
@pool = make_pool(**options)
end
attr :master_name
Signature
-
attribute
String
The name of the master instance.
attr :role
Signature
-
attribute
Symbol
The role of the instance that you want to connect to.
def resolve_address(role = @role)
Resolve an address for the specified role.
Signature
-
parameter
role
Symbol
The role to resolve (:master or :slave).
-
returns
Endpoint
The resolved endpoint address.
Implementation
def resolve_address(role = @role)
case role
when :master
resolve_master
when :slave
resolve_slave
else
raise ArgumentError, "Unknown instance role #{role}"
end => address
Console.debug(self, "Resolved #{@role} address: #{address}")
address or raise RuntimeError, "Unable to fetch #{role} via Sentinel."
end
def close
Close the sentinel client and all connections.
Implementation
def close
super
@sentinels.each do |_, client|
client.close
end
end
def failover(name = @master_name)
Initiate a failover for the specified master.
Signature
-
parameter
name
String
The name of the master to failover.
-
returns
Object
The result of the failover command.
Implementation
def failover(name = @master_name)
sentinels do |client|
return client.call("SENTINEL", "FAILOVER", name)
end
end
def masters
Get information about all masters.
Signature
-
returns
Array(Hash)
Array of master information hashes.
Implementation
def masters
sentinels do |client|
return client.call("SENTINEL", "MASTERS").map{|fields| fields.each_slice(2).to_h}
end
end
def master(name = @master_name)
Get information about a specific master.
Signature
-
parameter
name
String
The name of the master.
-
returns
Hash
The master information hash.
Implementation
def master(name = @master_name)
sentinels do |client|
return client.call("SENTINEL", "MASTER", name).each_slice(2).to_h
end
end
def resolve_master(options = @master_options)
Resolve the master endpoint address.
Signature
-
returns
Endpoint | Nil
The master endpoint or nil if not found.
Implementation
def resolve_master(options = @master_options)
sentinels do |client|
begin
address = client.call("SENTINEL", "GET-MASTER-ADDR-BY-NAME", @master_name)
rescue Errno::ECONNREFUSED
next
end
return Endpoint.for(nil, address[0], port: address[1], **options) if address
end
return nil
end
def resolve_slave(options = @slave_options)
Resolve a slave endpoint address.
Signature
-
returns
Endpoint | Nil
A slave endpoint or nil if not found.
Implementation
def resolve_slave(options = @slave_options)
sentinels do |client|
begin
reply = client.call("SENTINEL", "SLAVES", @master_name)
rescue Errno::ECONNREFUSED
next
end
slaves = available_slaves(reply)
next if slaves.empty?
slave = select_slave(slaves)
return Endpoint.for(nil, slave["ip"], port: slave["port"], **options)
end
return nil
end
def make_pool(**options)
Override the parent method. The only difference is that this one needs to resolve the master/slave address.
Implementation
def make_pool(**options)
self.assign_default_tags(options[:tags] ||= {})
Async::Pool::Controller.wrap(**options) do
endpoint = resolve_address
peer = endpoint.connect
stream = ::IO::Stream(peer)
endpoint.protocol.client(stream)
end
end