# frozen_string_literal: true require 'English' require 'socket' require 'timeout' require 'dalli/pid_cache' module Dalli module Protocol ## # Manages the socket connection to the server, including ensuring liveness # and retries. ## class ConnectionManager DEFAULTS = { # seconds between trying to contact a remote server down_retry_delay: 30, # connect/read/write timeout for socket operations socket_timeout: 1, # times a socket operation may fail before considering the server dead socket_max_failures: 2, # amount of time to sleep between retries when a failure occurs socket_failure_delay: 0.1, # Set keepalive keepalive: true }.freeze attr_accessor :hostname, :port, :socket_type, :options attr_reader :sock def initialize(hostname, port, socket_type, client_options) @hostname = hostname @port = port @socket_type = socket_type @options = DEFAULTS.merge(client_options) @request_in_progress = false @sock = nil @pid = nil reset_down_info end def name if socket_type == :unix hostname else "#{hostname}:#{port}" end end def establish_connection Dalli.logger.debug { "Dalli::Server#connect #{name}" } @sock = memcached_socket @pid = PIDCache.pid @request_in_progress = false rescue SystemCallError, *TIMEOUT_ERRORS, EOFError, SocketError => e # SocketError = DNS resolution failure error_on_request!(e) end def reconnect_down_server? return true unless @last_down_at time_to_next_reconnect = @last_down_at + options[:down_retry_delay] - Time.now return true unless time_to_next_reconnect.positive? Dalli.logger.debug do format('down_retry_delay not reached for %s (%