lib/redis_failover/client.rb in redis_failover-0.3.0 vs lib/redis_failover/client.rb in redis_failover-0.4.0
- old
+ new
@@ -7,11 +7,10 @@
include Util
RETRY_WAIT_TIME = 3
REDIS_ERRORS = Errno.constants.map { |c| Errno.const_get(c) }.freeze
REDIS_READ_OPS = Set[
- :dbsize,
:echo,
:exists,
:get,
:getbit,
:getrange,
@@ -20,30 +19,25 @@
:hgetall,
:hkeys,
:hlen,
:hmget,
:hvals,
- :info,
:keys,
- :lastsave,
:lindex,
:llen,
:lrange,
:mapped_hmget,
:mapped_mget,
:mget,
- :ping,
:scard,
:sdiff,
- :select,
:sinter,
:sismember,
:smembers,
:srandmember,
:strlen,
:sunion,
- :ttl,
:type,
:zcard,
:zcount,
:zrange,
:zrangebyscore,
@@ -52,10 +46,16 @@
:zrevrangebyscore,
:zrevrank,
:zscore
].freeze
+ UNSUPPORTED_OPS = Set[
+ :select,
+ :ttl,
+ :dbsize,
+ ].freeze
+
# Performance optimization: to avoid unnecessary method_missing calls,
# we proactively define methods that dispatch to the underlying redis
# calls.
Redis.public_instance_methods(false).each do |method|
define_method(method) do |*args, &block|
@@ -86,11 +86,10 @@
@retry = options[:retry_failure] || true
@max_retries = @retry ? options.fetch(:max_retries, 3) : 0
@server_url = "http://#{options[:host]}:#{options[:port]}/redis_servers"
@master = nil
@slaves = []
- @lock = Mutex.new
build_clients
start_background_monitor
end
def method_missing(method, *args, &block)
@@ -115,10 +114,11 @@
def redis_operation?(method)
Redis.public_instance_methods(false).include?(method)
end
def dispatch(method, *args, &block)
+ verify_supported!(method)
tries = 0
begin
if REDIS_READ_OPS.include?(method)
# send read operations to a slave
@@ -157,36 +157,34 @@
end
master
end
def build_clients
- @lock.synchronize do
- tries = 0
+ tries = 0
- begin
- logger.info('Checking for new redis nodes.')
- nodes = fetch_nodes
- return unless nodes_changed?(nodes)
+ begin
+ logger.info('Checking for new redis nodes.')
+ nodes = fetch_nodes
+ return unless nodes_changed?(nodes)
- logger.info('Node change detected, rebuilding clients.')
- master = new_clients_for(nodes[:master]).first if nodes[:master]
- slaves = new_clients_for(*nodes[:slaves])
+ logger.info('Node change detected, rebuilding clients.')
+ master = new_clients_for(nodes[:master]).first if nodes[:master]
+ slaves = new_clients_for(*nodes[:slaves])
- # once clients are successfully created, swap the references
- @master = master
- @slaves = slaves
- rescue => ex
- logger.error("Failed to fetch nodes from #{@server_url} - #{ex.message}")
- logger.error(ex.backtrace.join("\n"))
+ # once clients are successfully created, swap the references
+ @master = master
+ @slaves = slaves
+ rescue => ex
+ logger.error("Failed to fetch nodes from #{@server_url} - #{ex.message}")
+ logger.error(ex.backtrace.join("\n"))
- if tries < @max_retries
- tries += 1
- sleep(RETRY_WAIT_TIME) && retry
- end
-
- raise FailoverServerUnreachableError.new(@server_url)
+ if tries < @max_retries
+ tries += 1
+ sleep(RETRY_WAIT_TIME) && retry
end
+
+ raise FailoverServerUnavailableError.new(@server_url)
end
end
def fetch_nodes
open(@server_url) do |io|
@@ -220,9 +218,15 @@
current_role = node.info['role']
if current_role.to_sym != role
raise InvalidNodeRoleError.new(address_for(node), role, current_role)
end
role
+ end
+
+ def verify_supported!(method)
+ if UNSUPPORTED_OPS.include?(method)
+ raise UnsupportedOperationError.new(method)
+ end
end
def addresses_for(nodes)
nodes.map { |node| address_for(node) }
end