Class: Mongo::Server::Monitor Private
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Forwardable
|
|
|
Instance Chain:
|
|
| Inherits: | Object |
| Defined in: | lib/mongo/server/monitor.rb, lib/mongo/server/monitor/app_metadata.rb, lib/mongo/server/monitor/connection.rb |
Overview
Responsible for periodically polling a server via hello commands to keep the server's status up to date.
Does all work in a background thread so as to not interfere with other operations performed by the driver.
Constant Summary
-
DEFAULT_HEARTBEAT_INTERVAL =
# File 'lib/mongo/server/monitor.rb', line 36
The default interval between server status refreshes is 10 seconds.
10 -
MIN_SCAN_INTERVAL =
# File 'lib/mongo/server/monitor.rb', line 42
The minimum time between forced server scans. Is minHeartbeatFrequencyMS in the SDAM spec.
0.5 -
RTT_WEIGHT_FACTOR =
# File 'lib/mongo/server/monitor.rb', line 48Deprecated.
Will be removed in version 3.0.
The weighting factor (alpha) for calculating the average moving round trip time.
0.2
::Mongo::Loggable - Included
Class Method Summary
-
.new(server, event_listeners, monitoring, options = {}) ⇒ Monitor
constructor
Internal use only
Create the new server monitor.
Instance Attribute Summary
- #connection ⇒ Mongo::Server::Monitor::Connection readonly Internal use only
- #monitoring ⇒ Monitoring readonly Internal use only
- #options ⇒ Hash readonly Internal use only
- #server ⇒ Server readonly Internal use only
-
#rtt_measurement_only? ⇒ true | false
readonly
private
Internal use only
Returns whether this scan is only an RTT measurement, which is the case when the streaming protocol is active: a dedicated connection is already established and the
PushMonitoris running as the authoritative SDAM source. -
#streaming_enabled? ⇒ true | false
readonly
private
Internal use only
Returns whether the streaming protocol is enabled, based on the serverMonitoringMode option.
::Mongo::BackgroundThread - Included
::Mongo::Event::Publisher - Included
Instance Method Summary
- #create_push_monitor!(topology_version) Internal use only
-
#do_work
Internal use only
Perform a check of the server.
-
#heartbeat_interval ⇒ Float
Internal use only
The interval between regular server checks.
- #push_monitor ⇒ Server::PushMonitor | nil Internal use only
-
#restart! ⇒ Thread
Internal use only
Restarts the server monitor unless the current thread is alive.
- #run_sdam_flow(result, awaited: false, scan_error: nil, rtt_only: false) Internal use only
-
#scan! ⇒ Description
Internal use only
Perform a check of the server with throttling, and update the server's description and average round trip time.
-
#stop! ⇒ true | false
Stop the background thread and wait for it to terminate for a reasonable amount of time.
- #stop_push_monitor! Internal use only
- #to_s Internal use only
- #check private Internal use only
- #do_scan(publish_heartbeat: true) private Internal use only
- #pre_stop private Internal use only
- #throttle_scan_frequency! private Internal use only
::Mongo::BackgroundThread - Included
| #run! | Start the background thread. |
| #stop! | Stop the background thread and wait for to terminate for a reasonable amount of time. |
| #do_work | Override this method to do the work in the background thread. |
| #pre_stop | Override this method to perform additional signaling for the background thread to stop. |
| #start!, | |
| #wait_for_stop | Waits for the thread to die, with a timeout. |
::Mongo::Event::Publisher - Included
| #publish | Publish the provided event. |
::Mongo::Loggable - Included
| #log_debug | Convenience method to log debug messages with the standard prefix. |
| #log_error | Convenience method to log error messages with the standard prefix. |
| #log_fatal | Convenience method to log fatal messages with the standard prefix. |
| #log_info | Convenience method to log info messages with the standard prefix. |
| #log_warn | Convenience method to log warn messages with the standard prefix. |
| #logger | Get the logger instance. |
| #_mongo_log_prefix, #format_message | |
Constructor Details
.new(server, event_listeners, monitoring, options = {}) ⇒ Monitor
Monitor must never be directly instantiated outside of a ::Mongo::Server.
Create the new server monitor.
# File 'lib/mongo/server/monitor.rb', line 76
def initialize(server, event_listeners, monitoring, = {}) raise ArgumentError, "Wrong monitoring type: #{monitoring.inspect}" unless monitoring.is_a?(Monitoring) raise ArgumentError, 'App metadata is required' unless [:] raise ArgumentError, 'Push monitor app metadata is required' unless [:] @server = server @event_listeners = event_listeners @monitoring = monitoring @options = .freeze @mutex = Mutex.new @sdam_mutex = Mutex.new @next_earliest_scan = @next_wanted_scan = Time.now @update_mutex = Mutex.new end
Instance Attribute Details
#connection ⇒ Mongo::Server::Monitor::Connection (readonly)
# File 'lib/mongo/server/monitor.rb', line 96
attr_reader :connection
#monitoring ⇒ Monitoring (readonly)
# File 'lib/mongo/server/monitor.rb', line 118
attr_reader :monitoring
#options ⇒ Hash (readonly)
# File 'lib/mongo/server/monitor.rb', line 99
attr_reader :
#rtt_measurement_only? ⇒ true | false (readonly, private)
Returns whether this scan is only an RTT measurement, which is the case
when the streaming protocol is active: a dedicated connection is already
established and the PushMonitor is running as the authoritative SDAM
source. In the polling protocol there is no running PushMonitor, so the
connection-reuse check is a real server check and not RTT-only.
# File 'lib/mongo/server/monitor.rb', line 312
def rtt_measurement_only? return false if @connection.nil? # Only suppress the check while the server is in a known state and the # PushMonitor is the authoritative streaming source. If the server is # Unknown (e.g. an operation error or a streaming failure just marked # it so), the polling Monitor must run a full check to recover it # rather than waiting for the next streaming response - otherwise the # server can stay Unknown long enough to fail server selection. return false if server.unknown? pm = push_monitor !pm.nil? && pm.running? end
#server ⇒ Server (readonly)
# File 'lib/mongo/server/monitor.rb', line 93
attr_reader :server
#streaming_enabled? ⇒ true | false (readonly, private)
Returns whether the streaming protocol is enabled, based on the
serverMonitoringMode option. Default mode is :auto.
:stream- always use streaming when server supports it:poll- never use streaming:auto- use polling on FaaS platforms, streaming otherwise
# File 'lib/mongo/server/monitor.rb', line 387
def streaming_enabled? mode = [:server_monitoring_mode] || :auto case mode when :poll false when :stream true when :auto !Server::AppMetadata::Environment.new.faas? end end
Instance Method Details
#check (private)
# File 'lib/mongo/server/monitor.rb', line 327
def check if @connection && @connection.pid != Process.pid log_warn("Detected PID change - Mongo client should have been reconnected (old pid #{@connection.pid}, new pid #{Process.pid}") @connection.disconnect! @connection = nil end if @connection result = server.round_trip_time_calculator.measure do doc = @connection.check_document cmd = Protocol::Query.new( Database::ADMIN, Database::COMMAND, doc, limit: -1 ) = @connection.dispatch_bytes(cmd.serialize.to_s) .documents.first rescue Mongo::Error @connection.disconnect! @connection = nil raise end else connection = Connection.new(server.address, ) connection.connect! result = server.round_trip_time_calculator.measure do connection.handshake! end @connection = connection if (tv_doc = result['topologyVersion']) if streaming_enabled? create_push_monitor!(TopologyVersion.new(tv_doc)) push_monitor.run! else stop_push_monitor! end else # Failed response or pre-4.4 server stop_push_monitor! end result end result end
#create_push_monitor!(topology_version)
# File 'lib/mongo/server/monitor.rb', line 162
def create_push_monitor!(topology_version) @update_mutex.synchronize do @push_monitor = nil if @push_monitor && !@push_monitor.running? @push_monitor ||= PushMonitor.new( self, topology_version, monitoring, **Utils.shallow_symbolize_keys(.merge( socket_timeout: heartbeat_interval + connection.socket_timeout, app_metadata: [:], check_document: @connection.check_document )) ) end end
#do_scan(publish_heartbeat: true) (private)
# File 'lib/mongo/server/monitor.rb', line 288
def do_scan(publish_heartbeat: true) if publish_heartbeat monitoring.publish_heartbeat(server) do check end else check end rescue StandardError => e msg = "Error checking #{server.address}" Utils.warn_bg_exception(msg, e, logger: [:logger], log_prefix: [:log_prefix], bg_error_backtrace: [:bg_error_backtrace]) raise e end
#do_work
Perform a check of the server.
# File 'lib/mongo/server/monitor.rb', line 131
def do_work scan! # @next_wanted_scan may be updated by the push monitor. # However we need to check for termination flag so that the monitor # thread exits when requested. loop do delta = @next_wanted_scan - Time.now break unless delta > 0 signaled = server.scan_semaphore.wait(delta) break if signaled || @stop_requested end end
#heartbeat_interval ⇒ Float
The interval between regular server checks.
# File 'lib/mongo/server/monitor.rb', line 104
def heartbeat_interval [:heartbeat_interval] || DEFAULT_HEARTBEAT_INTERVAL end
#pre_stop (private)
# File 'lib/mongo/server/monitor.rb', line 284
def pre_stop server.scan_semaphore.signal end
#push_monitor ⇒ Server::PushMonitor | nil
# File 'lib/mongo/server/monitor.rb', line 122
def push_monitor @update_mutex.synchronize do @push_monitor end end
#restart! ⇒ Thread
Restarts the server monitor unless the current thread is alive.
# File 'lib/mongo/server/monitor.rb', line 270
def restart! if @thread && @thread.alive? @thread else run! end end
#run_sdam_flow(result, awaited: false, scan_error: nil, rtt_only: false)
# File 'lib/mongo/server/monitor.rb', line 230
def run_sdam_flow(result, awaited: false, scan_error: nil, rtt_only: false) @sdam_mutex.synchronize do old_description = server.description # An RTT-only measurement (streaming protocol active) must not update # the topology or publish SDAM events. The RTT it gathered is # incorporated into the next streaming-hello description via the # shared RTT calculator. The scheduling below still runs so the # monitor keeps pacing its checks. unless rtt_only new_description = Description.new( server.address, result, average_round_trip_time: server.round_trip_time_calculator.average_round_trip_time, minimum_round_trip_time: server.round_trip_time_calculator.minimum_round_trip_time ) server.cluster.run_sdam_flow(server.description, new_description, awaited: awaited, scan_error: scan_error) end server.description.tap do |new_description| unless awaited if new_description.unknown? && !old_description.unknown? @next_earliest_scan = @next_wanted_scan = Time.now else @next_earliest_scan = Time.now + MIN_SCAN_INTERVAL @next_wanted_scan = Time.now + heartbeat_interval end end end end end
#scan! ⇒ Description
If the system clock moves backwards, this method can sleep for a very long time.
The return value of this method is deprecated. In version 3.0.0 this method will not have a return value.
Perform a check of the server with throttling, and update the server's description and average round trip time.
If the server was checked less than MIN_SCAN_INTERVAL seconds ago, sleep until MIN_SCAN_INTERVAL seconds have passed since the last check. Then perform the check which involves running hello on the server being monitored and updating the server description as a result.
# File 'lib/mongo/server/monitor.rb', line 206
def scan! # Ordinarily the background thread would invoke this method. # But it is also possible to invoke scan! directly on a monitor. # Allow only one scan to be performed at a time. @mutex.synchronize do throttle_scan_frequency! # When the streaming protocol is active the PushMonitor is the # authoritative SDAM source and this scan only measures RTT on the # dedicated connection. Per the Server Monitoring spec, an RTT # command MUST NOT publish events or update the topology. Compute # this before do_scan, which may (re)connect and change the state. rtt_only = rtt_measurement_only? begin result = do_scan(publish_heartbeat: !rtt_only) rescue StandardError => e run_sdam_flow({}, scan_error: e, rtt_only: rtt_only) else run_sdam_flow(result, rtt_only: rtt_only) end end end
#stop! ⇒ true | false
Stop the background thread and wait for it to terminate for a reasonable amount of time.
# File 'lib/mongo/server/monitor.rb', line 151
def stop! stop_push_monitor! # Forward super's return value super.tap do # Important: disconnect should happen after the background thread # terminates. connection&.disconnect! end end
#stop_push_monitor!
# File 'lib/mongo/server/monitor.rb', line 179
def stop_push_monitor! @update_mutex.synchronize do if @push_monitor @push_monitor.stop! @push_monitor = nil end end end
#throttle_scan_frequency! (private)
If the system clock is set to a time in the past, this method can sleep for a very long time.
# File 'lib/mongo/server/monitor.rb', line 372
def throttle_scan_frequency! delta = @next_earliest_scan - Time.now return unless delta > 0 sleep(delta) end