Async::RedisSourceAsyncRedisSentinelClient

class SentinelClient

A Redis Sentinel client for high availability Redis deployments.

Definitions

def initialize(endpoints, master_name: DEFAULT_MASTER_NAME, role: :master, protocol: Protocol::RESP2, **options)

Create a new instance of the SentinelClient.

Implementation

def initialize(endpoints, master_name: DEFAULT_MASTER_NAME, role: :master, protocol: Protocol::RESP2, **options)
	@endpoints = endpoints
	@master_name = master_name
	@role = role
	@protocol = protocol
	
	# 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

Resolve the master endpoint address.

Signature

returns Endpoint | Nil

The master endpoint or nil if not found.

Implementation

def resolve_master
	sentinels do |client|
		begin
			address = client.call("SENTINEL", "GET-MASTER-ADDR-BY-NAME", @master_name)
		rescue Errno::ECONNREFUSED
			next
		end
		
		return Endpoint.remote(address[0], address[1]) if address
	end
	
	return nil
end

def resolve_slave

Resolve a slave endpoint address.

Signature

returns Endpoint | Nil

A slave endpoint or nil if not found.

Implementation

def resolve_slave
	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.remote(slave["ip"], slave["port"])
	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)
		
		@protocol.client(stream)
	end
end