lib/redis-sentinel/client.rb in redis-sentinel-1.3.0 vs lib/redis-sentinel/client.rb in redis-sentinel-1.4.0
- old
+ new
@@ -2,15 +2,18 @@
class Redis::Client
DEFAULT_FAILOVER_RECONNECT_WAIT_SECONDS = 0.1
class_eval do
+ attr_reader :current_sentinel
+ attr_reader :current_sentinel_options
+
def initialize_with_sentinel(options={})
options = options.dup # Don't touch my options
@master_name = fetch_option(options, :master_name)
@master_password = fetch_option(options, :master_password)
- @sentinels = fetch_option(options, :sentinels)
+ @sentinels_options = _parse_sentinel_options(fetch_option(options, :sentinels))
@failover_reconnect_timeout = fetch_option(options, :failover_reconnect_timeout)
@failover_reconnect_wait = fetch_option(options, :failover_reconnect_wait) ||
DEFAULT_FAILOVER_RECONNECT_WAIT_SECONDS
initialize_without_sentinel(options)
@@ -32,11 +35,11 @@
alias connect_without_sentinel connect
alias connect connect_with_sentinel
def sentinel?
- @master_name && @sentinels
+ @master_name && @sentinels_options
end
def auto_retry_with_timeout(&block)
deadline = @failover_reconnect_timeout.to_i + Time.now.to_f
begin
@@ -47,49 +50,56 @@
retry
end
end
def try_next_sentinel
- @sentinels << @sentinels.shift
- if @logger && @logger.debug?
- @logger.debug "Trying next sentinel: #{@sentinels[0][:host]}:#{@sentinels[0][:port]}"
+ sentinel_options = @sentinels_options.shift
+ if sentinel_options
+ @logger.debug "Trying next sentinel: #{sentinel_options[:host]}:#{sentinel_options[:port]}" if @logger && @logger.debug?
+ @current_sentinel_options = sentinel_options
+ @current_sentinel = Redis.new sentinel_options
+ else
+ raise Redis::CannotConnectError
end
- return @sentinels[0]
end
+ def refresh_sentinels_list
+ responses = current_sentinel.sentinel("sentinels", @master_name)
+ @sentinels_options = responses.map do |response|
+ {:host => response[3], :port => response[5]}
+ end.unshift(:host => current_sentinel_options[:host], :port => current_sentinel_options[:port])
+ end
+
def discover_master
while true
- sentinel = redis_sentinels[@sentinels[0]]
+ try_next_sentinel
begin
- host, port = sentinel.sentinel("get-master-addr-by-name", @master_name)
- if !host && !port
- raise Redis::ConnectionError.new("No master named: #{@master_name}")
+ master_host, master_port = current_sentinel.sentinel("get-master-addr-by-name", @master_name)
+ if master_host && master_port
+ # An ip:port pair
+ @options.merge!(:host => master_host, :port => master_port.to_i, :password => @master_password)
+ refresh_sentinels_list
+ break
+ else
+ # A null reply
end
- is_down, runid = sentinel.sentinel("is-master-down-by-addr", host, port)
- break
+ rescue Redis::CommandError
+ # An -IDONTKNOWN reply
rescue Redis::CannotConnectError
- try_next_sentinel
+ # faile to connect to current sentinel server
end
end
-
- if is_down.to_s == "1" || runid == '?'
- raise Redis::CannotConnectError.new("The master: #{@master_name} is currently not available.")
- else
- @options.merge!(:host => host, :port => port.to_i, :password => @master_password)
- end
end
- def reconnect_with_sentinels
- redis_sentinels.each do |config, sentinel|
- sentinel.client.reconnect
- end
- reconnect_without_sentinels
+ def disconnect_with_sentinels
+ current_sentinel.client.disconnect if current_sentinel
+ disconnect_without_sentinels
end
- alias reconnect_without_sentinels reconnect
- alias reconnect reconnect_with_sentinels
+ alias disconnect_without_sentinels disconnect
+ alias disconnect disconnect_with_sentinels
def call_with_readonly_protection(*args, &block)
tries = 0
call_without_readonly_protection(*args, &block)
rescue Redis::CommandError => e
@@ -108,12 +118,24 @@
def fetch_option(options, key)
options.delete(key) || options.delete(key.to_s)
end
- def redis_sentinels
- @redis_sentinels ||= Hash.new do |hash, config|
- hash[config] = Redis.new(config)
+ def _parse_sentinel_options(options)
+ return if options.nil?
+
+ sentinel_options = []
+ options.each do |sentinel_option|
+ if sentinel_option.is_a?(Hash)
+ sentinel_options << sentinel_option
+ else
+ uri = URI.parse(sentinel_option)
+ sentinel_options << {
+ host: uri.host,
+ port: uri.port
+ }
+ end
end
+ sentinel_options
end
end
end