lib/net/tcp_client/tcp_client.rb
def connect
      start_time = Time.now
      retries    = 0
      close

      # Number of times to try
      begin
        connect_to_server(servers, policy)
        logger.info(message: "Connected to #{address}", duration: (Time.now - start_time) * 1000) if respond_to?(:logger)
      rescue ConnectionFailure, ConnectionTimeout => exception
        cause = exception.is_a?(ConnectionTimeout) ? exception : exception.cause
        # Retry-able?
        if self.class.reconnect_on_errors.include?(cause.class) && (retries < connect_retry_count.to_i)
          retries += 1
          logger.warn "#connect Failed to connect to any of #{servers.join(',')}. Sleeping:#{connect_retry_interval}s. Retry: #{retries}" if respond_to?(:logger)
          sleep(connect_retry_interval)
          retry
        else
          message = "#connect Failed to connect to any of #{servers.join(',')} after #{retries} retries. #{exception.class}: #{exception.message}"
          logger.benchmark_error(message, exception: exception, duration: (Time.now - start_time)) if respond_to?(:logger)
          raise ConnectionFailure.new(message, address.to_s, cause)
        end
      end
    end
def connect
      start_time = Time.now
      retries    = 0
      close

      # Number of times to try
      begin
        connect_to_server(servers, policy)
        logger.info(message: "Connected to #{address}", duration: (Time.now - start_time) * 1000) if respond_to?(:logger)
      rescue ConnectionFailure, ConnectionTimeout => exception
        cause = exception.is_a?(ConnectionTimeout) ? exception : exception.cause
        # Retry-able?
        if self.class.reconnect_on_errors.include?(cause.class) && (retries < connect_retry_count.to_i)
          retries += 1
          logger.warn "#connect Failed to connect to any of #{servers.join(',')}. Sleeping:#{connect_retry_interval}s. Retry: #{retries}" if respond_to?(:logger)
          sleep(connect_retry_interval)
          retry
        else
          message = "#connect Failed to connect to any of #{servers.join(',')} after #{retries} retries. #{exception.class}: #{exception.message}"
          logger.benchmark_error(message, exception: exception, duration: (Time.now - start_time)) if respond_to?(:logger)
          raise ConnectionFailure.new(message, address.to_s, cause)
        end
      end
    end
Create a new TCP Client connection

 Parameters:
   :server [String]
     URL of the server to connect to with port number
     'localhost:2000'
     '192.168.1.10:80'

   :servers [Array of String]
     Array of URL's of servers to connect to with port numbers
     ['server1:2000', 'server2:2000']

     The second server will only be attempted once the first server
     cannot be connected to or has timed out on connect
     A read failure or timeout will not result in switching to the second
     server, only a connection failure or during an automatic reconnect

   :connect_timeout [Float]
     Time in seconds to timeout when trying to connect to the server
     A value of -1 will cause the connect wait time to be infinite
     Default: 10 seconds

   :read_timeout [Float]
     Time in seconds to timeout on read
     Can be overridden by supplying a timeout in the read call
     Default: 60

   :write_timeout [Float]
     Time in seconds to timeout on write
     Can be overridden by supplying a timeout in the write call
     Default: 60

   :buffered [true|false]
     Whether to use Nagle's Buffering algorithm (http://en.wikipedia.org/wiki/Nagle's_algorithm)
     Recommend disabling for RPC style invocations where we don't want to wait for an
     ACK from the server before sending the last partial segment
     Buffering is recommended in a browser or file transfer style environment
     where multiple sends are expected during a single response.
     Also sets sync to true if buffered is false so that all data is sent immediately without
     internal buffering.
     Default: true

   :keepalive [true|false]
     Makes the OS check connections even when not in use, so that failed connections fail immediately
     upon use instead of possibly taking considerable time to fail.
     Default: true

   :connect_retry_count [Fixnum]
     Number of times to retry connecting when a connection fails
     Default: 10

   :connect_retry_interval [Float]
     Number of seconds between connection retry attempts after the first failed attempt
     Default: 0.5

   :retry_count [Fixnum]
     Number of times to retry when calling #retry_on_connection_failure
     This is independent of :connect_retry_count which still applies with
     connection failures. This retry controls upto how many times to retry the
     supplied block should a connection failure occur during the block
     Default: 3

   :on_connect [Proc]
     Directly after a connection is established and before it is made available
     for use this Block is invoked.
     Typical Use Cases:
     - Initialize per connection session sequence numbers.
     - Pass authentication information to the server.
     - Perform a handshake with the server.

   :policy [Symbol|Proc]
     Specify the policy to use when connecting to servers.
       :ordered
         Select a server in the order supplied in the array, with the first
         having the highest priority. The second server will only be connected
         to if the first server is unreachable
       :random
         Randomly select a server from the list every time a connection
         is established, including during automatic connection recovery.
       :ping_time
         FUTURE - Not implemented yet - Pull request anyone?
         The server with the lowest ping time will be tried first
       Proc:
         When a Proc is supplied, it will be called passing in the list
         of servers. The Proc must return one server name
           Example:
             :policy => Proc.new do |servers|
               servers.last
             end
       Default: :ordered

   :close_on_error [True|False]
     To prevent the connection from going into an inconsistent state
     automatically close the connection if an error occurs
     This includes a Read Timeout
     Default: true

   :proxy_server [String]
     The host name and port in the form of 'host_name:1234' to forward
     socket connections though.
     Default: nil ( none )

   SSL Options
   :ssl [true|false|Hash]
      true:  SSL is enabled using the SSL context defaults.
      false: SSL is not used.
      Hash:
        Keys from OpenSSL::SSL::SSLContext:
          ca_file, ca_path, cert, cert_store, ciphers, key, ssl_timeout, ssl_version
          verify_callback, verify_depth, verify_mode
        handshake_timeout: [Float]
          The number of seconds to timeout the SSL Handshake.
          Default: connect_timeout
      Default: false.
        See OpenSSL::SSL::SSLContext::DEFAULT_PARAMS for the defaults.

 Example:
   client = Net::TCPClient.new(
     server:                 'server:3300',
     connect_retry_interval: 0.1,
     connect_retry_count:    5
   )

   client.retry_on_connection_failure do
     client.write('Update the database')
   end

   # Read upto 20 characters from the server
   response = client.read(20)

   puts "Received: #{response}"
   client.close

 SSL Example:
   client = Net::TCPClient.new(
     server:                 'server:3300',
     connect_retry_interval: 0.1,
     connect_retry_count:    5,
     ssl:                    true
   )

 SSL with options Example:
   client = Net::TCPClient.new(
     server:                 'server:3300',
     connect_retry_interval: 0.1,
     connect_retry_count:    5,
     ssl:                    {
       verify_mode: OpenSSL::SSL::VERIFY_NONE
     }
   )
 Connect to the TCP server

 Raises Net::TCPClient::ConnectionTimeout when the time taken to create a connection
        exceeds the :connect_timeout
 Raises Net::TCPClient::ConnectionFailure whenever Socket raises an error such as Error::EACCESS etc, see Socket#connect for more information

 Error handling is implemented as follows:
 1. TCP Socket Connect failure:
    Cannot reach server
    Server is being restarted, or is not running
    Retry 50 times every 100ms before raising a Net::TCPClient::ConnectionFailure
    - Means all calls to #connect will take at least 5 seconds before failing if the server is not running
    - Allows hot restart of server process if it restarts within 5 seconds

 2. TCP Socket Connect timeout:
    Timed out after 5 seconds trying to connect to the server
    Usually means server is busy or the remote server disappeared off the network recently
    No retry, just raise a Net::TCPClient::ConnectionTimeout

 Note: When multiple servers are supplied it will only try to connect to
       the subsequent servers once the retry count has been exceeded

 Note: Calling #connect on an open connection will close the current connection
       and create a new connection