Class: Dalli::Protocol::ConnectionManager
- Inherits:
-
Object
- Object
- Dalli::Protocol::ConnectionManager
- Defined in:
- lib/dalli/protocol/connection_manager.rb
Overview
Manages the socket connection to the server, including ensuring liveness and retries.
Constant Summary collapse
- 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
Instance Attribute Summary collapse
-
#hostname ⇒ Object
Returns the value of attribute hostname.
-
#options ⇒ Object
Returns the value of attribute options.
-
#port ⇒ Object
Returns the value of attribute port.
-
#sock ⇒ Object
readonly
Returns the value of attribute sock.
-
#socket_type ⇒ Object
Returns the value of attribute socket_type.
Instance Method Summary collapse
- #abort_request! ⇒ Object
- #close ⇒ Object
- #close_on_fork ⇒ Object
- #confirm_in_progress! ⇒ Object
- #confirm_ready! ⇒ Object
- #connected? ⇒ Boolean
-
#down! ⇒ Object
Marks the server instance as down.
- #error_on_request!(err_or_string) ⇒ Object
- #establish_connection ⇒ Object
- #finish_request! ⇒ Object
- #fork_detected? ⇒ Boolean
-
#initialize(hostname, port, socket_type, client_options) ⇒ ConnectionManager
constructor
A new instance of ConnectionManager.
- #log_down_detected ⇒ Object
- #log_up_detected ⇒ Object
- #log_warn_message(err_or_string) ⇒ Object
- #max_allowed_failures ⇒ Object
- #memcached_socket ⇒ Object
- #name ⇒ Object
- #raise_down_error ⇒ Object
- #read(count) ⇒ Object
- #read_line ⇒ Object
-
#read_nonblock ⇒ Object
Non-blocking read.
- #reconnect!(message) ⇒ Object
- #reconnect_down_server? ⇒ Boolean
- #request_in_progress? ⇒ Boolean
- #reset_down_info ⇒ Object
- #socket_timeout ⇒ Object
- #start_request! ⇒ Object
- #up! ⇒ Object
- #write(bytes) ⇒ Object
Constructor Details
#initialize(hostname, port, socket_type, client_options) ⇒ ConnectionManager
Returns a new instance of ConnectionManager.
32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/dalli/protocol/connection_manager.rb', line 32 def initialize(hostname, port, socket_type, ) @hostname = hostname @port = port @socket_type = socket_type @options = DEFAULTS.merge() @request_in_progress = false @sock = nil @pid = nil reset_down_info end |
Instance Attribute Details
#hostname ⇒ Object
Returns the value of attribute hostname.
29 30 31 |
# File 'lib/dalli/protocol/connection_manager.rb', line 29 def hostname @hostname end |
#options ⇒ Object
Returns the value of attribute options.
29 30 31 |
# File 'lib/dalli/protocol/connection_manager.rb', line 29 def @options end |
#port ⇒ Object
Returns the value of attribute port.
29 30 31 |
# File 'lib/dalli/protocol/connection_manager.rb', line 29 def port @port end |
#sock ⇒ Object (readonly)
Returns the value of attribute sock.
30 31 32 |
# File 'lib/dalli/protocol/connection_manager.rb', line 30 def sock @sock end |
#socket_type ⇒ Object
Returns the value of attribute socket_type.
29 30 31 |
# File 'lib/dalli/protocol/connection_manager.rb', line 29 def socket_type @socket_type end |
Instance Method Details
#abort_request! ⇒ Object
145 146 147 |
# File 'lib/dalli/protocol/connection_manager.rb', line 145 def abort_request! @request_in_progress = false end |
#close ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/dalli/protocol/connection_manager.rb', line 112 def close return unless @sock begin @sock.close rescue StandardError nil end @sock = nil @pid = nil abort_request! end |
#close_on_fork ⇒ Object
222 223 224 225 226 227 228 229 |
# File 'lib/dalli/protocol/connection_manager.rb', line 222 def close_on_fork = 'Fork detected, re-connecting child process...' Dalli.logger.info { } # Close socket on a fork, setting us up for reconnect # on next request. close raise Dalli::NetworkError, end |
#confirm_in_progress! ⇒ Object
106 107 108 109 110 |
# File 'lib/dalli/protocol/connection_manager.rb', line 106 def confirm_in_progress! raise '[Dalli] No request in progress. This may be a bug in Dalli.' unless request_in_progress? close_on_fork if fork_detected? end |
#confirm_ready! ⇒ Object
101 102 103 104 |
# File 'lib/dalli/protocol/connection_manager.rb', line 101 def confirm_ready! close if request_in_progress? close_on_fork if fork_detected? end |
#connected? ⇒ Boolean
125 126 127 |
# File 'lib/dalli/protocol/connection_manager.rb', line 125 def connected? !@sock.nil? end |
#down! ⇒ Object
Marks the server instance as down. Updates the down_at state and raises an Dalli::NetworkError that includes the underlying error in the message. Calls close to clean up socket state
84 85 86 87 88 89 90 91 |
# File 'lib/dalli/protocol/connection_manager.rb', line 84 def down! close log_down_detected @error = $ERROR_INFO&.class&.name @msg ||= $ERROR_INFO&. raise_down_error end |
#error_on_request!(err_or_string) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/dalli/protocol/connection_manager.rb', line 179 def error_on_request!(err_or_string) (err_or_string) @fail_count += 1 if @fail_count >= max_allowed_failures down! else # Closes the existing socket, setting up for a reconnect # on next request reconnect!('Socket operation failed, retrying...') end end |
#establish_connection ⇒ Object
52 53 54 55 56 57 58 59 60 61 |
# File 'lib/dalli/protocol/connection_manager.rb', line 52 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 |
#finish_request! ⇒ Object
139 140 141 142 143 |
# File 'lib/dalli/protocol/connection_manager.rb', line 139 def finish_request! raise '[Dalli] No request in progress. This may be a bug in Dalli.' unless @request_in_progress @request_in_progress = false end |
#fork_detected? ⇒ Boolean
231 232 233 |
# File 'lib/dalli/protocol/connection_manager.rb', line 231 def fork_detected? @pid && @pid != PIDCache.pid end |
#log_down_detected ⇒ Object
235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/dalli/protocol/connection_manager.rb', line 235 def log_down_detected @last_down_at = Time.now if @down_at time = Time.now - @down_at Dalli.logger.debug { format('%<name>s is still down (for %<time>.3f seconds now)', name: name, time: time) } else @down_at = @last_down_at Dalli.logger.warn("#{name} is down") end end |
#log_up_detected ⇒ Object
247 248 249 250 251 252 |
# File 'lib/dalli/protocol/connection_manager.rb', line 247 def log_up_detected return unless @down_at time = Time.now - @down_at Dalli.logger.warn { format('%<name>s is back (downtime was %<time>.3f seconds)', name: name, time: time) } end |
#log_warn_message(err_or_string) ⇒ Object
214 215 216 217 218 219 220 |
# File 'lib/dalli/protocol/connection_manager.rb', line 214 def (err_or_string) detail = err_or_string.is_a?(String) ? err_or_string : "#{err_or_string.class}: #{err_or_string.}" Dalli.logger.warn do detail = err_or_string.is_a?(String) ? err_or_string : "#{err_or_string.class}: #{err_or_string.}" "#{name} failed (count: #{@fail_count}) #{detail}" end end |
#max_allowed_failures ⇒ Object
175 176 177 |
# File 'lib/dalli/protocol/connection_manager.rb', line 175 def max_allowed_failures @max_allowed_failures ||= @options[:socket_max_failures] || 2 end |
#memcached_socket ⇒ Object
206 207 208 209 210 211 212 |
# File 'lib/dalli/protocol/connection_manager.rb', line 206 def memcached_socket if socket_type == :unix Dalli::Socket::UNIX.open(hostname, ) else Dalli::Socket::TCP.open(hostname, port, ) end end |
#name ⇒ Object
44 45 46 47 48 49 50 |
# File 'lib/dalli/protocol/connection_manager.rb', line 44 def name if socket_type == :unix hostname else "#{hostname}:#{port}" end end |
#raise_down_error ⇒ Object
93 94 95 |
# File 'lib/dalli/protocol/connection_manager.rb', line 93 def raise_down_error raise Dalli::NetworkError, "#{name} is down: #{@error} #{@msg}" end |
#read(count) ⇒ Object
157 158 159 160 161 |
# File 'lib/dalli/protocol/connection_manager.rb', line 157 def read(count) @sock.readfull(count) rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e error_on_request!(e) end |
#read_line ⇒ Object
149 150 151 152 153 154 155 |
# File 'lib/dalli/protocol/connection_manager.rb', line 149 def read_line data = @sock.gets("\r\n") error_on_request!('EOF in read_line') if data.nil? data rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e error_on_request!(e) end |
#read_nonblock ⇒ Object
Non-blocking read. Here to support the operation of the get_multi operation
171 172 173 |
# File 'lib/dalli/protocol/connection_manager.rb', line 171 def read_nonblock @sock.read_available end |
#reconnect!(message) ⇒ Object
192 193 194 195 196 |
# File 'lib/dalli/protocol/connection_manager.rb', line 192 def reconnect!() close sleep([:socket_failure_delay]) if [:socket_failure_delay] raise Dalli::NetworkError, end |
#reconnect_down_server? ⇒ Boolean
63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/dalli/protocol/connection_manager.rb', line 63 def reconnect_down_server? return true unless @last_down_at time_to_next_reconnect = @last_down_at + [:down_retry_delay] - Time.now return true unless time_to_next_reconnect.positive? Dalli.logger.debug do format('down_retry_delay not reached for %<name>s (%<time>.3f seconds left)', name: name, time: time_to_next_reconnect) end false end |
#request_in_progress? ⇒ Boolean
129 130 131 |
# File 'lib/dalli/protocol/connection_manager.rb', line 129 def request_in_progress? @request_in_progress end |
#reset_down_info ⇒ Object
198 199 200 201 202 203 204 |
# File 'lib/dalli/protocol/connection_manager.rb', line 198 def reset_down_info @fail_count = 0 @down_at = nil @last_down_at = nil @msg = nil @error = nil end |
#socket_timeout ⇒ Object
97 98 99 |
# File 'lib/dalli/protocol/connection_manager.rb', line 97 def socket_timeout @socket_timeout ||= @options[:socket_timeout] end |
#start_request! ⇒ Object
133 134 135 136 137 |
# File 'lib/dalli/protocol/connection_manager.rb', line 133 def start_request! raise '[Dalli] Request already in progress. This may be a bug in Dalli.' if @request_in_progress @request_in_progress = true end |
#up! ⇒ Object
76 77 78 79 |
# File 'lib/dalli/protocol/connection_manager.rb', line 76 def up! log_up_detected reset_down_info end |
#write(bytes) ⇒ Object
163 164 165 166 167 |
# File 'lib/dalli/protocol/connection_manager.rb', line 163 def write(bytes) @sock.write(bytes) rescue SystemCallError, *TIMEOUT_ERRORS => e error_on_request!(e) end |