module NewRelic::Agent::AgentHelpers::Connect
This module is an artifact of a refactoring of the connect method - all of its methods are used in that context, so it can be refactored at will. It should be fully tested
Attributes
number of attempts we’ve made to contact the server
Public Instance Methods
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 186 def connect(options = {}) opts = connect_options(options) return unless should_connect?(opts[:force_reconnect]) ::NewRelic::Agent.logger.debug("Connecting Process to New Relic: #$0") connect_to_server @connected_pid = $$ @connect_state = :connected signal_connected NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::HEALTHY) rescue NewRelic::Agent::ForceDisconnectException => e handle_force_disconnect(e) rescue NewRelic::Agent::LicenseException => e handle_license_error(e) rescue NewRelic::Agent::UnrecoverableAgentException => e handle_unrecoverable_agent_error(e) rescue StandardError, Timeout::Error, NewRelic::Agent::ServerConnectionException => e NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_CONNECT) retry if retry_from_error?(e, opts) rescue Exception => e ::NewRelic::Agent.logger.error('Exception of unexpected type during Agent#connect():', e) raise end
Establish a connection to New Relic servers.
By default, if a connection has already been established, this method will be a no-op.
@param [Hash] options @option options [Boolean] :keep_retrying (true)
If true, this method will block until a connection is successfully established, continuing to retry upon failure. If false, this method will return after either successfully connecting, or after failing once.
@option options [Boolean] :force_reconnect (false)
If true, this method will force establishment of a new connection with New Relic, even if there is already an existing connection. This is useful primarily when re-establishing a new connection after forking off from a parent process.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 161 def connect_options(options) { keep_retrying: true, force_reconnect: Agent.config[:force_reconnect] }.merge(options) end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 45 def connect_retry_period NewRelic::CONNECT_RETRY_PERIODS[connect_attempts] || NewRelic::MAX_RETRY_PERIOD end
Per the spec at /agents/agent-specs/Collector-Response-Handling.md, retry connections after a specific backoff sequence to prevent hammering the server.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 99 def connect_to_server request_builder = ::NewRelic::Agent::Connect::RequestBuilder.new( @service, Agent.config, event_harvest_config, environment_for_connect ) connect_response = @service.connect(request_builder.connect_payload) response_handler = ::NewRelic::Agent::Connect::ResponseHandler.new(self, Agent.config) response_handler.configure_agent(connect_response) log_connection(connect_response) if connect_response connect_response end
Builds the payload to send to the connect service, connects, then configures the agent using the response from the connect service
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 22 def connected? @connect_state == :connected end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 17 def disconnect @connect_state = :disconnected true end
Disconnect just sets the connect state to disconnected, preventing further retries.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 26 def disconnected? @connect_state == :disconnected end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 86 def environment_for_connect @environment_report ||= Agent.config[:send_environment_info] ? Array(EnvironmentReport.new) : [] end
Checks whether we should send environment info, and if so, returns the snapshot from the local environment. Generating the EnvironmentReport
has the potential to trigger require calls in Rails environments, so this method should only be called synchronously from on the main thread.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 92 def event_harvest_config @event_harvest_config ||= Configuration::EventHarvestConfig.from_config(Agent.config) end
Constructs and memoizes an event_harvest_config
hash to be used in the payload sent during connect (and reconnect)
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 68 def handle_license_error(error) ::NewRelic::Agent.logger.error(error.message, 'Visit newrelic.com to obtain a valid license key, or to upgrade your account.') NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::INVALID_LICENSE_KEY) disconnect end
When the server sends us an error with the license key, we want to tell the user that something went wrong, and let them know where to go to get a valid license key
After this runs, it disconnects the agent so that it will no longer try to connect to the server, saving the application and the server load
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 75 def handle_unrecoverable_agent_error(error) ::NewRelic::Agent.logger.error(error.message) disconnect shutdown end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 126 def log_collector_messages(messages) messages.each do |message| ::NewRelic::Agent.logger.send(message['level'].downcase, message['message']) end end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 117 def log_connection(config_data) ::NewRelic::Agent.logger.debug("Connected to NewRelic Service at #{@service.collector.name}") ::NewRelic::Agent.logger.debug("Agent Run = #{@service.agent_id}.") ::NewRelic::Agent.logger.debug("Connection data = #{config_data.inspect}") if config_data['messages']&.any? log_collector_messages(config_data['messages']) end end
Logs when we connect to the server, for debugging purposes
-
makes sure we know if an agent has not connected
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 56 def log_error(error) ::NewRelic::Agent.logger.error("Error establishing connection with New Relic Service at #{control.server}:", error) end
When we have a problem connecting to the server, we need to tell the user what happened, since this is not an error we can handle gracefully.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 49 def note_connect_failure self.connect_attempts += 1 end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 211 def retry_from_error?(e, opts) # Allow a killed (aborting) thread to continue exiting during shutdown. # See: https://github.com/newrelic/newrelic-ruby-agent/issues/340 raise if Thread.current.status == 'aborting' log_error(e) return false unless opts[:keep_retrying] note_connect_failure ::NewRelic::Agent.logger.info("Will re-attempt in #{connect_retry_period} seconds") sleep(connect_retry_period) true end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 30 def serverless? Agent.config[:'serverless_mode.enabled'] end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 37 def should_connect?(force = false) force || (!connected? && !disconnected?) end
Don’t connect if we’re already connected, if we’re in serverless mode, or if we tried to connect and were rejected with prejudice because of a license issue, unless we’re forced to by force_reconnect.
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 140 def signal_connected @wait_on_connect_mutex.synchronize do @wait_on_connect_condition.signal end end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 146 def wait_on_connect(timeout) return if connected? @waited_on_connect = true NewRelic::Agent.logger.debug('Waiting on connect to complete.') @wait_on_connect_mutex.synchronize do @wait_on_connect_condition.wait(@wait_on_connect_mutex, timeout) end unless connected? raise WaitOnConnectTimeout, "Agent was unable to connect in #{timeout} seconds." end end
Source
# File lib/new_relic/agent/agent_helpers/connect.rb, line 136 def waited_on_connect? @waited_on_connect end
Used for testing to let us know we’ve actually started to wait