lib/redis_failover/client.rb in redis_failover-0.9.7.2 vs lib/redis_failover/client.rb in redis_failover-1.0.0

- old
+ new

@@ -38,19 +38,21 @@ # Creates a new failover redis client. # # @param [Hash] options the options used to initialize the client instance # @option options [String] :zkservers comma-separated ZooKeeper host:port + # @option options [String] :zk an existing ZK client connection instance # @option options [String] :znode_path znode path override for redis nodes # @option options [String] :password password for redis nodes # @option options [String] :db database to use for redis nodes # @option options [String] :namespace namespace for redis nodes # @option options [Logger] :logger logger override # @option options [Boolean] :retry_failure indicates if failures are retried # @option options [Integer] :max_retries max retries for a failure # @option options [Boolean] :safe_mode indicates if safe mode is used or not # @option options [Boolean] :master_only indicates if only redis master is used + # @note Use either :zkservers or :zk # @return [RedisFailover::Client] def initialize(options = {}) Util.logger = options[:logger] if options[:logger] @master = nil @slaves = [] @@ -131,11 +133,11 @@ # # @param [Hash] options the options used for manual failover # @option options [String] :host the host of the failover candidate # @option options [String] :port the port of the failover candidate def manual_failover(options = {}) - ManualFailover.new(@zk, options).perform + ManualFailover.new(@zk, @root_znode, options).perform self end # Gracefully performs a shutdown of this client. This method is # mostly useful when the client is used in a forking environment. @@ -175,17 +177,17 @@ private # Sets up the underlying ZooKeeper connection. def setup_zk - @zk = ZK.new(@zkservers) - @zk.watcher.register(@znode) { |event| handle_zk_event(event) } + @zk = ZK.new(@zkservers) if @zkservers + @zk.register(redis_nodes_path) { |event| handle_zk_event(event) } if @safe_mode @zk.on_expired_session { purge_clients } end - @zk.on_connected { @zk.stat(@znode, :watch => true) } - @zk.stat(@znode, :watch => true) + @zk.on_connected { @zk.stat(redis_nodes_path, :watch => true) } + @zk.stat(redis_nodes_path, :watch => true) update_znode_timestamp end # Handles a ZK event. # @@ -194,16 +196,16 @@ update_znode_timestamp if event.node_created? || event.node_changed? build_clients elsif event.node_deleted? purge_clients - @zk.stat(@znode, :watch => true) + @zk.stat(redis_nodes_path, :watch => true) else logger.error("Unknown ZK node event: #{event.inspect}") end ensure - @zk.stat(@znode, :watch => true) + @zk.stat(redis_nodes_path, :watch => true) end # Determines if a method is a known redis operation. # # @param [Symbol] method the method to check @@ -308,19 +310,23 @@ # Fetches the known redis nodes from ZooKeeper. # # @return [Hash] the known master/slave redis servers def fetch_nodes - data = @zk.get(@znode, :watch => true).first + data = @zk.get(redis_nodes_path, :watch => true).first nodes = symbolize_keys(decode(data)) logger.debug("Fetched nodes: #{nodes.inspect}") nodes rescue Zookeeper::Exceptions::InheritedConnectionError => ex logger.debug { "Caught #{ex.class} '#{ex.message}' - reopening ZK client" } @zk.reopen retry + rescue *ZK_ERRORS => ex + logger.warn { "Caught #{ex.class} '#{ex.message}' - retrying" } + sleep(RETRY_WAIT_TIME) + retry end # Builds new Redis clients for the specified nodes. # # @param [Array<String>] nodes the array of redis host:port pairs @@ -473,17 +479,26 @@ # Parses the configuration operations. # # @param [Hash] options the configuration options def parse_options(options) - @zkservers = options.fetch(:zkservers) { raise ArgumentError, ':zkservers required'} - @znode = options.fetch(:znode_path, Util::DEFAULT_ZNODE_PATH) + @zk, @zkservers = options.values_at(:zk, :zkservers) + if [@zk, @zkservers].all? || [@zk, @zkservers].none? + raise ArgumentError, 'must specify :zk or :zkservers' + end + + @root_znode = options.fetch(:znode_path, Util::DEFAULT_ROOT_ZNODE_PATH) @namespace = options[:namespace] @password = options[:password] @db = options[:db] @retry = options.fetch(:retry_failure, true) @max_retries = @retry ? options.fetch(:max_retries, 3) : 0 @safe_mode = options.fetch(:safe_mode, true) @master_only = options.fetch(:master_only, false) + end + + # @return [String] the znode path for the master redis nodes config + def redis_nodes_path + "#{@root_znode}/nodes" end end end