class RedisWmrs::SlaveClient

Constants

MASTER_PRIORITY

Public Class Methods

ip_and_hostnames() click to toggle source
# File lib/redis_wmrs/slave_client.rb, line 84
def self.ip_and_hostnames
  unless @my_hostname
    @my_hostname = Socket::gethostname rescue nil
    @my_ip = IPSocket::getaddress(@my_hostname) rescue nil
  end
  return @my_hostname, @my_ip
end

Public Instance Methods

connect() click to toggle source

override Redis::Client#connect overwritten by redis-sentinel github.com/flyerhzm/redis-sentinel/blob/master/lib/redis-sentinel/client.rb#L24

# File lib/redis_wmrs/slave_client.rb, line 8
def connect
  if sentinel?
    auto_retry_with_timeout do
      discover_slave
      begin
        connect_without_sentinel
      rescue => e
        @failed ||= []
        f = "#{@options[:host]}:#{@options[:port]}"
        @failed.delete(f)
        @failed.push(f) # 必ず末尾に追加する
        raise e
      else
        @failed.delete("#{@options[:host]}:#{@options[:port]}") if @failed
      end
    end
  else
    connect_without_sentinel
  end
end
discover_slave() click to toggle source
# File lib/redis_wmrs/slave_client.rb, line 29
def discover_slave
  while true
    try_next_sentinel
    host_attrs = fetch_slaves
    host_attrs.each do |attrs|
      begin
        host, port = attrs["ip"], attrs["port"]
        if host && port
          # An ip:port pair
          @options.merge!(:host => host, :port => port.to_i, :password => @master_password)
          refresh_sentinels_list
          return
        else
          # A null reply
        end
      rescue Redis::CommandError => e
        raise unless e.message.include?("IDONTKNOW")
      rescue Redis::CannotConnectError
        # faile to connect to current sentinel server
      end
    end
  end
end

Private Instance Methods

fetch_slaves() click to toggle source
# File lib/redis_wmrs/slave_client.rb, line 55
def fetch_slaves
  preferred_indexes = []
  slave_attrs_array = current_sentinel.sentinel("slaves", @master_name).map{|pairs| Hash[*pairs]}
  # masterと同じサーバで動作しているクライアントの場合、slaveではなく
  # masterに繋ぐべきなのでマスタも接続先に追加します。
  master_attrs_array = slave_attrs_array.map{|h|
    {"ip" => h["master-host"], "port" => h["master-port"], "slave-priority" => MASTER_PRIORITY}
  }.uniq
  attrs_array = slave_attrs_array + master_attrs_array
  [*self.class.ip_and_hostnames, "127.0.0.1", "localhost"].compact.each do |ip_hostname|
    if idx = attrs_array.index{|attrs| attrs["ip"] ==  ip_hostname}
      preferred_indexes << idx
    end
  end
  # slave-priorityの値が小さいほどmasterに昇格しやすいので、
  # preferredではないslaves群についてはslave-priorityの降順で接続の優先順位を振ります。
  not_preferred = ((0...attrs_array.length).to_a - preferred_indexes).
    sort_by{|i| attrs_array[i]["slave-priority"].to_i}.reverse
  result = (preferred_indexes + not_preferred).map{|i| attrs_array[i]}
  # 接続に失敗した接続先は優先度を下げます
  (@failed || []).each do |failed|
    if idx = result.index{|r| failed == "#{r['ip']}:#{r['port']}" }
      result.push(result.delete_at(idx))
    end
  end
  return result
end