Class: Ably::Realtime::Connection::ConnectionManager Private
- Inherits:
-
Object
- Object
- Ably::Realtime::Connection::ConnectionManager
- Defined in:
- lib/ably/realtime/connection/connection_manager.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
ConnectionManager is responsible for all actions relating to underlying connection and transports, such as opening, closing, attempting reconnects etc. Connection state changes are performed by this class and executed from ConnectionStateMachine
This is a private class and should never be used directly by developers as the API is likely to change in future.
Constant Summary collapse
- CONNECT_RETRY_CONFIG =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Configuration for automatic recovery of failed connection attempts
{ disconnected: { retry_every: 15, max_time_in_state: 120 }, suspended: { retry_every: 120, max_time_in_state: Float::INFINITY } }.freeze
- TIMEOUTS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Time to wait following a connection state request before it’s considered a failure
{ open: 15, close: 10 }
- RESOLVABLE_ERROR_CODES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Error codes from the server that can potentially be resolved
{ token_expired: 40140 }
Instance Method Summary collapse
-
#close_connection ⇒ Object
private
Send a Close Models::ProtocolMessage to the server and release the transport.
-
#connected(protocol_message) ⇒ Object
private
Called whenever a new connection is made.
-
#connection_opening_failed(error) ⇒ Object
private
Called by the transport when a connection attempt fails.
-
#destroy_transport ⇒ Object
private
Ensures the underlying transport has been disconnected and all event emitter callbacks removed.
-
#error_received_from_server(error) ⇒ Object
private
ProtocolMessage Error received from server.
-
#fail(error) ⇒ Object
private
Connection has failed.
-
#force_close_connection ⇒ Object
private
Close the underlying transport immediately and set the connection state to closed.
-
#initialize(connection) ⇒ ConnectionManager
constructor
private
A new instance of ConnectionManager.
-
#reconnect_transport ⇒ Object
private
Reconnect the WebsocketTransport if possible, otherwise set up a new transport.
-
#respond_to_transport_disconnected_when_connecting(current_transition) ⇒ Object
private
When a connection is disconnected whilst connecting, attempt reconnect and/or set state to :suspended or :failed.
-
#respond_to_transport_disconnected_whilst_connected(current_transition) ⇒ Object
private
When a connection is disconnected after connecting, attempt reconnect and/or set state to :suspended or :failed.
-
#retry_count_for_state(state) ⇒ Integer
private
Number of consecutive attempts for provided state.
-
#setup_transport {|Ably::Realtime::Connection::WebsocketTransport| ... } ⇒ Object
private
Creates and sets up a new WebsocketTransport available on attribute #transport.
Constructor Details
#initialize(connection) ⇒ ConnectionManager
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of ConnectionManager.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 28 def initialize(connection) @connection = connection @timers = Hash.new { |hash, key| hash[key] = [] } connection.unsafe_on(:closed) do connection.reset_resume_info end connection.unsafe_once(:connecting) do close_connection_when_reactor_is_stopped end EventMachine.next_tick do # Connect once Connection object is initialised connection.connect if client.auto_connect end end |
Instance Method Details
#close_connection ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Send a Close Models::ProtocolMessage to the server and release the transport
125 126 127 128 129 130 131 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 125 def close_connection connection.(action: Ably::Models::ProtocolMessage::ACTION.Close) create_timeout_timer_whilst_in_state(:close, TIMEOUTS.fetch(:close)) do force_close_connection if connection.closing? end end |
#connected(protocol_message) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Called whenever a new connection is made
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 84 def connected() if connection.key if .connection_key == connection.key logger.debug "ConnectionManager: Connection resumed successfully - ID #{connection.id} and key #{connection.key}" EventMachine.next_tick { connection.resumed } else logger.debug "ConnectionManager: Connection was not resumed, old connection ID #{connection.id} has been updated with new connect ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" detach_attached_channels .error connection.configure_new .connection_id, .connection_key, .connection_serial end else logger.debug "ConnectionManager: New connection created with ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" connection.configure_new .connection_id, .connection_key, .connection_serial end end |
#connection_opening_failed(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Called by the transport when a connection attempt fails
76 77 78 79 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 76 def connection_opening_failed(error) logger.warn "ConnectionManager: Connection to #{connection.current_host}:#{connection.port} failed; #{error.message}" connection.transition_state_machine next_retry_state, Ably::Exceptions::ConnectionError.new("Connection failed: #{error.message}", nil, 80000) end |
#destroy_transport ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Ensures the underlying transport has been disconnected and all event emitter callbacks removed
103 104 105 106 107 108 109 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 103 def destroy_transport if transport unsubscribe_from_transport_events transport transport.close_connection connection.release_websocket_transport end end |
#error_received_from_server(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
ProtocolMessage Error received from server. Some error states can be resolved by the client library.
193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 193 def error_received_from_server(error) case error.code when RESOLVABLE_ERROR_CODES.fetch(:token_expired) connection.transition_state_machine :disconnected connection.unsafe_once_or_if(:disconnected) do renew_token_and_reconnect error end else logger.error "ConnectionManager: Error #{error.class.name} code #{error.code} received from server '#{error.message}', transitioning to failed state" connection.transition_state_machine :failed, error end end |
#fail(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Connection has failed
144 145 146 147 148 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 144 def fail(error) connection.logger.fatal "ConnectionManager: Connection failed - #{error}" connection.manager.destroy_transport connection.unsafe_once(:failed) { connection.emit :error, error } end |
#force_close_connection ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Close the underlying transport immediately and set the connection state to closed
136 137 138 139 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 136 def force_close_connection destroy_transport connection.transition_state_machine :closed end |
#reconnect_transport ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Reconnect the WebsocketTransport if possible, otherwise set up a new transport
114 115 116 117 118 119 120 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 114 def reconnect_transport if !transport || transport.disconnected? setup_transport else transport.reconnect connection.current_host, connection.port end end |
#respond_to_transport_disconnected_when_connecting(current_transition) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
When a connection is disconnected whilst connecting, attempt reconnect and/or set state to :suspended or :failed
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 153 def respond_to_transport_disconnected_when_connecting(current_transition) return unless connection.disconnected? || connection.suspended? # do nothing if state has changed through an explicit request return unless retry_connection? # do not always reattempt connection or change state as client may be re-authorising error = current_transition. if error.kind_of?(Ably::Models::ErrorInfo) renew_token_and_reconnect error if error.code == RESOLVABLE_ERROR_CODES.fetch(:token_expired) return end unless connection_retry_from_suspended_state? return if connection_retry_for(:disconnected, ignore_states: [:connecting]) end return if connection_retry_for(:suspended, ignore_states: [:connecting]) # Fallback if no other criteria met connection.transition_state_machine :failed, current_transition. end |
#respond_to_transport_disconnected_whilst_connected(current_transition) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
When a connection is disconnected after connecting, attempt reconnect and/or set state to :suspended or :failed
176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 176 def respond_to_transport_disconnected_whilst_connected(current_transition) logger.warn "ConnectionManager: Connection to #{connection.transport.url} was disconnected unexpectedly" error = current_transition. if error.kind_of?(Ably::Models::ErrorInfo) && error.code != RESOLVABLE_ERROR_CODES.fetch(:token_expired) connection.emit :error, error logger.error "ConnectionManager: Error in Disconnected ProtocolMessage received from the server - #{error}" end destroy_transport respond_to_transport_disconnected_when_connecting current_transition end |
#retry_count_for_state(state) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Number of consecutive attempts for provided state
209 210 211 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 209 def retry_count_for_state(state) retries_for_state(state, ignore_states: [:connecting]).count end |
#setup_transport {|Ably::Realtime::Connection::WebsocketTransport| ... } ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates and sets up a new WebsocketTransport available on attribute #transport
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/ably/realtime/connection/connection_manager.rb', line 50 def setup_transport if transport && !transport.ready_for_release? raise RuntimeError, 'Existing WebsocketTransport is connected, and must be closed first' end unless client.auth.authentication_security_requirements_met? connection.transition_state_machine :failed, Ably::Exceptions::InsecureRequestError.new('Cannot use Basic Auth over non-TLS connections', 401, 40103) return end logger.debug 'ConnectionManager: Opening a websocket transport connection' connection.create_websocket_transport do |websocket_transport| subscribe_to_transport_events websocket_transport yield websocket_transport if block_given? end logger.debug "ConnectionManager: Setting up automatic connection timeout timer for #{TIMEOUTS.fetch(:open)}s" create_timeout_timer_whilst_in_state(:connect, TIMEOUTS.fetch(:open)) do connection_opening_failed Ably::Exceptions::ConnectionTimeoutError.new("Connection to Ably timed out after #{TIMEOUTS.fetch(:open)}s", nil, 80014) end end |