class EM::Voldemort::Connection
TCP connection to one Voldemort
node. The connection can be used to access multiple stores. Automatically reconnects if the connection is lost, but does not automatically retry failed requests (that is the cluster’s job).
Constants
- DEFAULT_PROTOCOL
- REQUEST_TIMEOUT
- STATUS_CHECK_PERIOD
Attributes
Public Class Methods
# File lib/em-voldemort/connection.rb, line 12 def initialize(options={}) @host = options[:host] or raise ArgumentError, "#{self.class.name} requires :host" @port = options[:port] or raise ArgumentError, "#{self.class.name} requires :port" @node_id = options[:node_id] @protocol = options[:protocol] || DEFAULT_PROTOCOL @logger = options[:logger] || Logger.new($stdout) @health = :good end
Public Instance Methods
Waits for the outstanding request (if any) to complete, then gracefully shuts down the connection. Returns a deferrable that succeeds once the connection is closed (never fails).
# File lib/em-voldemort/connection.rb, line 38 def close return @closing_deferrable if @closing_deferrable @closing_deferrable = EM::DefaultDeferrable.new @timer.cancel if @handler @handler.close_gracefully else @closing_deferrable.succeed end @handler = FailHandler.new(self) @health = :bad @closing_deferrable end
Establishes a connection to the node. Calling connect
is optional, since it also happens automatically when you start making requests.
# File lib/em-voldemort/connection.rb, line 23 def connect force_connect unless @handler end
Called by the connection handler when the connection is closed for any reason (closed by us, closed by peer, rejected, timeout etc). Do not call from application code.
# File lib/em-voldemort/connection.rb, line 56 def connection_closed(handler, reason=nil) logger.info ["Connection to Voldemort node #{host}:#{port} closed", reason].compact.join(': ') @handler = FailHandler.new(self) if handler.equal? @handler @health = :bad @closing_deferrable.succeed if @closing_deferrable end
Sends a request to the node, given as a binary string (not including the request size prefix). Establishes a connection if necessary. If a request is already in progress, this request is queued up. Returns a deferrable that succeeds with the node’s response (again without the size prefix), or fails if there was a network-level error.
# File lib/em-voldemort/connection.rb, line 31 def send_request(request) connect @handler.enqueue_request(request) end
Private Instance Methods
# File lib/em-voldemort/connection.rb, line 82 def force_connect @timer ||= setup_status_check_timer(&method(:status_check)) @handler = EM.connect(host, port, Handler, self) @handler.in_flight.callback { @health = :good } # restore health if protocol negotiation succeeded rescue EventMachine::ConnectionError => e # A synchronous exception is typically thrown on DNS resolution failure logger.warn "Cannot connect to Voldemort node: #{e.class.name}: #{e.message}" connection_closed(@handler) @handler = FailHandler.new(self) end
# File lib/em-voldemort/connection.rb, line 65 def setup_status_check_timer EM.add_periodic_timer(STATUS_CHECK_PERIOD) { yield } end
# File lib/em-voldemort/connection.rb, line 69 def status_check if @closing_deferrable # Do nothing (don't reconnect once we've been asked to shut down). elsif !@handler || @handler.is_a?(FailHandler) # Connect for the first time, or reconnect after failure. force_connect elsif @handler.in_flight && Time.now - @handler.last_request >= REQUEST_TIMEOUT # Request timed out. Pronounce the connection dead, and reconnect. @handler.close_connection force_connect end end