class Mongo::Server::Monitor
Responsible for periodically polling a server via ismaster 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.
@since 2.0.0
Constants
- HEARTBEAT_FREQUENCY
The default time for a server to refresh its status is 10 seconds.
@since 2.0.0
- MIN_SCAN_FREQUENCY
The minimum time between forced server scans. Is minHeartbeatFrequencyMS in the SDAM spec.
@since 2.0.0
- RTT_WEIGHT_FACTOR
The weighting factor (alpha) for calculating the average moving round trip time.
@since 2.0.0 @deprecated Will be removed in version 3.0.
Attributes
@return [ Mongo::Server::Monitor::Connection
] connection The connection to use.
@return [ Monitoring
] monitoring The monitoring.
@return [ Hash ] options The server options.
@return [ Server
] server The server that this monitor is monitoring. @api private
Public Class Methods
Create the new server monitor.
@example Create the server monitor.
Mongo::Server::Monitor.new(address, listeners, monitoring)
@note Monitor
must never be directly instantiated outside of a Server
.
@param [ Server
] server The server to monitor. @param [ Event::Listeners
] event_listeners The event listeners. @param [ Monitoring
] monitoring The monitoring.. @param [ Hash ] options The options.
@option options [ Float ] :connect_timeout The timeout, in seconds, to
use when establishing the monitoring connection.
@option options [ Logger
] :logger A custom logger to use. @option options [ Float ] :socket_timeout The timeout, in seconds, to
execute operations on the monitoring connection.
@since 2.0.0 @api private
# File lib/mongo/server/monitor.rb, line 68 def initialize(server, event_listeners, monitoring, options = {}) unless monitoring.is_a?(Monitoring) raise ArgumentError, "Wrong monitoring type: #{monitoring.inspect}" end @server = server @event_listeners = event_listeners @monitoring = monitoring @options = options.freeze # This is a Mongo::Server::Monitor::Connection @connection = Connection.new(server.address, options) @mutex = Mutex.new @scan_started_at = nil end
Public Instance Methods
Runs the server monitor. Refreshing happens on a separate thread per server.
@example Run the monitor.
monitor.run
@return [ Thread ] The thread the monitor runs on.
@since 2.0.0
# File lib/mongo/server/monitor.rb, line 122 def do_work scan! server.scan_semaphore.wait(server.cluster.heartbeat_interval) end
Get the refresh interval for the server. This will be defined via an option or will default to 10.
@return [ Float ] The heartbeat interval, in seconds.
@since 2.0.0 @deprecated
# File lib/mongo/server/monitor.rb, line 109 def heartbeat_frequency server.cluster.heartbeat_interval end
Restarts the server monitor unless the current thread is alive.
@example Restart the monitor.
monitor.restart!
@return [ Thread ] The thread the monitor runs on.
@since 2.1.0
# File lib/mongo/server/monitor.rb, line 180 def restart! if @thread && @thread.alive? @thread else run! end end
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_FREQUENCY
seconds ago, sleep until MIN_SCAN_FREQUENCY
seconds have passed since the last check. Then perform the check which involves running isMaster on the server being monitored and updating the server description as a result.
@note If the system clock is set to a time in the past, this method
can sleep for a very long time.
@note The return value of this method is deprecated. In version 3.0.0
this method will not have a return value.
@example Run a scan.
monitor.scan!
@return [ Description
] The updated description.
@since 2.0.0
# File lib/mongo/server/monitor.rb, line 163 def scan! throttle_scan_frequency! result = ismaster new_description = Description.new(server.address, result, server.round_trip_time_averager.average_round_trip_time) server.cluster.run_sdam_flow(server.description, new_description) server.description end
Stop the background thread and wait for to terminate for a reasonable amount of time.
@return [ true | false ] Whether the thread was terminated.
@api public for backwards compatibility only
Mongo::BackgroundThread#stop!
# File lib/mongo/server/monitor.rb, line 133 def stop! # Forward super's return value super.tap do # Important: disconnect should happen after the background thread # terminated. connection.disconnect! end end
Private Instance Methods
# File lib/mongo/server/monitor.rb, line 194 def ismaster @mutex.synchronize do if monitoring.monitoring? monitoring.started( Monitoring::SERVER_HEARTBEAT, Monitoring::Event::ServerHeartbeatStarted.new(server.address) ) end result, exc, rtt, average_rtt = server.round_trip_time_averager.measure do connection.ismaster end if exc log_debug("Error running ismaster on #{server.address}: #{exc.class}: #{exc.message}") if monitoring.monitoring? monitoring.failed( Monitoring::SERVER_HEARTBEAT, Monitoring::Event::ServerHeartbeatFailed.new(server.address, rtt, exc) ) end result = {} else if monitoring.monitoring? monitoring.succeeded( Monitoring::SERVER_HEARTBEAT, Monitoring::Event::ServerHeartbeatSucceeded.new(server.address, rtt) ) end end result end end
# File lib/mongo/server/monitor.rb, line 190 def pre_stop server.scan_semaphore.signal end
@note 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 229 def throttle_scan_frequency! # Normally server.last_scan indicates when the previous scan # completed, but if scan! is manually invoked repeatedly then # server.last_scan won't be updated and multiple scans with no # cooldown can be obtained. Guard against repeated direct scan! # invocation also. last_time = [server.last_scan, @scan_started_at].compact.max if last_time difference = (Time.now - last_time) throttle_time = (MIN_SCAN_FREQUENCY - difference) sleep(throttle_time) if throttle_time > 0 end @scan_started_at = Time.now end