class Async::Redis::SentinelsClient

Public Class Methods

new(master_name, sentinels, role = :master, protocol = Protocol::RESP2, **options) click to toggle source
# File lib/async/redis/sentinels.rb, line 6
def initialize(master_name, sentinels, role = :master, protocol = Protocol::RESP2, **options)
        @master_name = master_name
        @sentinel_endpoints = sentinels.map do |sentinel|
                Async::IO::Endpoint.tcp(sentinel[:host], sentinel[:port])
        end
        @role = role

        @protocol = protocol
        @pool = connect(**options)
end

Private Instance Methods

available_slaves(slaves_cmd_reply) click to toggle source
# File lib/async/redis/sentinels.rb, line 77
def available_slaves(slaves_cmd_reply)
        # The reply is an array with the format: [field1, value1, field2,
        # value2, etc.].
        # When a slave is marked as down by the sentinel, the "flags" field
        # (comma-separated array) contains the "s_down" value.
        slaves_cmd_reply.map { |s| s.each_slice(2).to_h }
                                    .reject { |s| s.fetch('flags').split(',').include?('s_down') }
end
connect(**options) click to toggle source

Override the parent method. The only difference is that this one needs to resolve the master/slave address.

# File lib/async/redis/sentinels.rb, line 21
def connect(**options)
        Async::Pool::Controller.wrap(**options) do
                endpoint = resolve_address
                peer = endpoint.connect
                stream = IO::Stream.new(peer)

                @protocol.client(stream)
        end
end
resolve_address() click to toggle source
# File lib/async/redis/sentinels.rb, line 31
def resolve_address
        address = case @role
                                                when :master then resolve_master
                                                when :slave then resolve_slave
                                                else raise ArgumentError, "Unknown instance role #{@role}"
                                                end

        address or raise RuntimeError, "Unable to fetch #{@role} via Sentinel."
end
resolve_master() click to toggle source
# File lib/async/redis/sentinels.rb, line 41
def resolve_master
        @sentinel_endpoints.each do |sentinel_endpoint|
                client = Client.new(sentinel_endpoint)

                begin
                        address = client.call('sentinel', 'get-master-addr-by-name', @master_name)
                rescue Errno::ECONNREFUSED
                        next
                end

                return Async::IO::Endpoint.tcp(address[0], address[1]) if address
        end

        nil
end
resolve_slave() click to toggle source
# File lib/async/redis/sentinels.rb, line 57
def resolve_slave
        @sentinel_endpoints.each do |sentinel_endpoint|
                client = Client.new(sentinel_endpoint)

                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 Async::IO::Endpoint.tcp(slave['ip'], slave['port'])
        end

        nil
end
select_slave(available_slaves) click to toggle source
# File lib/async/redis/sentinels.rb, line 86
def select_slave(available_slaves)
        available_slaves.sample
end