Class: Mongo::Server

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Event::Publisher, Monitoring::Publishable
Defined in:
lib/mongo/server.rb,
lib/mongo/server/monitor.rb,
lib/mongo/server/connection.rb,
lib/mongo/server/description.rb,
lib/mongo/server/app_metadata.rb,
lib/mongo/server/push_monitor.rb,
lib/mongo/server/connection_base.rb,
lib/mongo/server/connection_pool.rb,
lib/mongo/server/connection_common.rb,
lib/mongo/server/monitor/connection.rb,
lib/mongo/server/pending_connection.rb,
lib/mongo/server/description/features.rb,
lib/mongo/server/monitor/app_metadata.rb,
lib/mongo/server/app_metadata/platform.rb,
lib/mongo/server/app_metadata/truncator.rb,
lib/mongo/server/push_monitor/connection.rb,
lib/mongo/server/app_metadata/environment.rb,
lib/mongo/server/connection_pool/populator.rb,
lib/mongo/server/description/load_balancer.rb,
lib/mongo/server/round_trip_time_calculator.rb,
lib/mongo/server/connection_pool/generation_manager.rb

Overview

Represents a single server on the server side that can be standalone, part of a replica set, or a mongos.

Since:

  • 2.0.0

Defined Under Namespace

Classes: AppMetadata, Connection, ConnectionBase, ConnectionCommon, ConnectionPool, Description, Monitor, PendingConnection, PushMonitor, RoundTripTimeCalculator

Constant Summary collapse

CONNECT_TIMEOUT =

The default time in seconds to timeout a connection attempt.

Since:

  • 2.4.3

10.freeze

Constants included from Loggable

Loggable::PREFIX

Instance Attribute Summary collapse

Attributes included from Event::Publisher

#event_listeners

Instance Method Summary collapse

Methods included from Event::Publisher

#publish

Methods included from Monitoring::Publishable

#publish_cmap_event, #publish_event, #publish_sdam_event

Methods included from Loggable

#log_debug, #log_error, #log_fatal, #log_info, #log_warn, #logger

Constructor Details

#initialize(address, cluster, monitoring, event_listeners, options = {}) ⇒ Server

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.

Note:

Server must never be directly instantiated outside of a Cluster.

Instantiate a new server object. Will start the background refresh and subscribe to the appropriate events.

Examples:

Initialize the server.

Mongo::Server.new('127.0.0.1:27017', cluster, monitoring, listeners)

Options Hash (options):

  • :monitor (Boolean)

    For internal driver use only: whether to monitor the server after instantiating it.

  • :monitoring_io (true, false)

    For internal driver use only. Set to false to prevent SDAM-related I/O from being done by this server. Note: setting this option to false will make the server non-functional. It is intended for use in tests which manually invoke SDAM state transitions.

  • :populator_io (true, false)

    For internal driver use only. Set to false to prevent the populator threads from being created and started in the server’s connection pool. It is intended for use in tests that also turn off monitoring_io, unless the populator is explicitly needed. If monitoring_io is off, but the populator_io is on, the populator needs to be manually closed at the end of the test, since a cluster without monitoring is considered not connected, and thus will not clean up the connection pool populator threads on close.

  • :load_balancer (true | false)

    Whether this server is a load balancer.

  • :connect (String)

    The client connection mode.

Since:

  • 2.0.0



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/mongo/server.rb', line 71

def initialize(address, cluster, monitoring, event_listeners, options = {})
  @address = address
  @cluster = cluster
  @monitoring = monitoring
  options = options.dup
  _monitor = options.delete(:monitor)
  @options = options.freeze
  @event_listeners = event_listeners
  @connection_id_gen = Class.new do
    include Id
  end
  @scan_semaphore = DistinguishingSemaphore.new
  @round_trip_time_calculator = RoundTripTimeCalculator.new
  @description = Description.new(address, {},
    load_balancer: !!@options[:load_balancer],
    force_load_balancer: force_load_balancer?,
  )
  @last_scan = nil
  @last_scan_monotime = nil
  unless options[:monitoring_io] == false
    @monitor = Monitor.new(self, event_listeners, monitoring,
      options.merge(
        app_metadata: cluster.,
        push_monitor_app_metadata: cluster.,
        heartbeat_interval: cluster.heartbeat_interval,
    ))
    unless _monitor == false
      start_monitoring
    end
  end
  @connected = true
  @pool_lock = Mutex.new
end

Instance Attribute Details

#addressString (readonly)

Returns The configured address for the server.

Since:

  • 2.0.0



106
107
108
# File 'lib/mongo/server.rb', line 106

def address
  @address
end

#clusterCluster (readonly)

Returns cluster The server cluster.

Since:

  • 2.0.0



109
110
111
# File 'lib/mongo/server.rb', line 109

def cluster
  @cluster
end

#descriptionServer::Description (readonly)

Returns description The server description the monitor refreshes.

Since:

  • 2.0.0



123
124
125
# File 'lib/mongo/server.rb', line 123

def description
  @description
end

#monitornil | Monitor (readonly)

Returns monitor The server monitor. nil if the servenr was created with monitoring_io: false option.

Since:

  • 2.0.0



113
114
115
# File 'lib/mongo/server.rb', line 113

def monitor
  @monitor
end

#monitoringMonitoring (readonly)

Returns monitoring The monitoring.

Since:

  • 2.0.0



119
120
121
# File 'lib/mongo/server.rb', line 119

def monitoring
  @monitoring
end

#optionsHash (readonly)

Returns The options hash.

Since:

  • 2.0.0



116
117
118
# File 'lib/mongo/server.rb', line 116

def options
  @options
end

#round_trip_time_calculatorRoundTripTimeCalculator (readonly)

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 Round trip time calculator object.

Since:

  • 2.0.0



235
236
237
# File 'lib/mongo/server.rb', line 235

def round_trip_time_calculator
  @round_trip_time_calculator
end

#scan_semaphoreSemaphore (readonly)

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 Semaphore to signal to request an immediate scan of this server by its monitor, if one is running.

Since:

  • 2.0.0



231
232
233
# File 'lib/mongo/server.rb', line 231

def scan_semaphore
  @scan_semaphore
end

Instance Method Details

#==(other) ⇒ true, false

Is this server equal to another?

Examples:

Is the server equal to the other?

server == other

Since:

  • 2.0.0



247
248
249
250
# File 'lib/mongo/server.rb', line 247

def ==(other)
  return false unless other.is_a?(Server)
  address == other.address
end

#clear_connection_pool(service_id: nil, interrupt_in_use_connections: false) ⇒ 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.

Since:

  • 2.0.0



675
676
677
678
679
680
681
682
683
684
685
# File 'lib/mongo/server.rb', line 675

def clear_connection_pool(service_id: nil, interrupt_in_use_connections: false)
  @pool_lock.synchronize do
    # A server being marked unknown after it is closed is technically
    # incorrect but it does not meaningfully alter any state.
    # Because historically the driver permitted servers to be marked
    # unknown at any time, continue doing so even if the pool is closed.
    if @pool && !@pool.closed?
      @pool.disconnect!(service_id: service_id, interrupt_in_use_connections: interrupt_in_use_connections)
    end
  end
end

#clear_descriptionObject

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.

Clear the servers description so that it is considered unknown and can be safely disconnected.

Since:

  • 2.0.0



665
666
667
# File 'lib/mongo/server.rb', line 665

def clear_description
  @description = Mongo::Server::Description.new(address, {})
end

#closeObject

Since:

  • 2.0.0



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/mongo/server.rb', line 296

def close
  if monitor
    monitor.stop!
  end

  @connected = false

  _pool = nil
  @pool_lock.synchronize do
    _pool, @pool = @pool, nil
  end

  # TODO: change this to _pool.close in RUBY-3174.
  # Clear the pool. If the server is not unknown then the
  # pool will stay ready. Stop the background populator thread.
  _pool&.close(stay_ready: true)

  nil
end

#compressorString | nil

Deprecated.
Note:

Compression is negotiated for each connection separately.

The compressor negotiated by the server monitor, if any.

This attribute is nil if no server check has not yet completed, and if no compression was negatiated.

Since:

  • 2.0.0



181
182
183
184
185
186
187
# File 'lib/mongo/server.rb', line 181

def compressor
  if monitor
    monitor.compressor
  else
    nil
  end
end

#connectable?true, false

Deprecated.

No longer necessary with Server Selection specification.

Determine if a connection to the server is able to be established and messages can be sent to it.

Examples:

Is the server connectable?

server.connectable?

Since:

  • 2.1.0



263
# File 'lib/mongo/server.rb', line 263

def connectable?; end

#connected?true|false

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.

Whether the server is connected.

Since:

  • 2.7.0



322
323
324
# File 'lib/mongo/server.rb', line 322

def connected?
  @connected
end

#disconnect!true

Disconnect the driver from this server.

Disconnects all idle connections to this server in its connection pool, if any exist. Stops the populator of the connection pool, if it is running. Does not immediately close connections which are presently checked out (i.e. in use) - such connections will be closed when they are returned to their respective connection pools. Stop the server’s background monitor.

Since:

  • 2.0.0



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/mongo/server.rb', line 277

def disconnect!
  if monitor
    monitor.stop!
  end

  @connected = false

  # The current CMAP spec requires a pool to be mostly unusable
  # if its server is unknown (or, therefore, disconnected).
  # However any outstanding operations should continue to completion,
  # and their connections need to be checked into the pool to be
  # torn down. Because of this cleanup requirement we cannot just
  # close the pool and set it to nil here, to be recreated the next
  # time the server is discovered.
  pool_internal&.clear

  true
end

#force_load_balancer?true | false

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 whether this server is forced to be a load balancer.

Since:

  • 2.0.0



130
131
132
# File 'lib/mongo/server.rb', line 130

def force_load_balancer?
  options[:connect] == :load_balanced
end

#handle_auth_failure!Object

Handle authentication failure.

Examples:

Handle possible authentication failure.

server.handle_auth_failure! do
  Auth.get(user).(self)
end

Raises:

Since:

  • 2.3.0



530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/mongo/server.rb', line 530

def handle_auth_failure!
  yield
rescue Mongo::Error::SocketTimeoutError
  # possibly cluster is slow, do not give up on it
  raise
rescue Mongo::Error::SocketError, Auth::Unauthorized => e
  # non-timeout network error or auth error, clear the pool and mark the
  # topology as unknown
  unknown!(
    generation: e.generation,
    service_id: e.service_id,
    stop_push_monitor: true,
  )
  raise
end

#handle_handshake_failure!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.

Handle handshake failure.

Since:

  • 2.7.0



507
508
509
510
511
512
513
514
515
516
# File 'lib/mongo/server.rb', line 507

def handle_handshake_failure!
  yield
rescue Mongo::Error::SocketError, Mongo::Error::SocketTimeoutError => e
  unknown!(
    generation: e.generation,
    service_id: e.service_id,
    stop_push_monitor: true,
  )
  raise
end

#heartbeat_frequencyObject Also known as: heartbeat_frequency_seconds

Deprecated.

Since:

  • 2.0.0



159
160
161
# File 'lib/mongo/server.rb', line 159

def heartbeat_frequency
  cluster.heartbeat_interval
end

#inspectString

Get a pretty printed server inspection.

Examples:

Get the server inspection.

server.inspect

Since:

  • 2.0.0



357
358
359
# File 'lib/mongo/server.rb', line 357

def inspect
  "#<Mongo::Server:0x#{object_id} address=#{address.host}:#{address.port} #{status}>"
end

#last_scanTime | nil

Returns last_scan The time when the last server scan completed, or nil if the server has not been scanned yet.

Since:

  • 2.4.0



138
139
140
141
142
143
144
# File 'lib/mongo/server.rb', line 138

def last_scan
  if description && !description.config.empty?
    description.last_update_time
  else
    @last_scan
  end
end

#last_scan_monotimeFloat | nil

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 last_scan_monotime The monotonic time when the last server scan completed, or nil if the server has not been scanned yet.

Since:

  • 2.0.0



149
150
151
152
153
154
155
# File 'lib/mongo/server.rb', line 149

def last_scan_monotime
  if description && !description.config.empty?
    description.last_update_monotime
  else
    @last_scan_monotime
  end
end

#matches_tag_set?(tag_set) ⇒ true, false

Determine if the provided tags are a subset of the server’s tags.

Examples:

Are the provided tags a subset of the server’s tags.

server.matches_tag_set?({ 'rack' => 'a', 'dc' => 'nyc' })

Since:

  • 2.0.0



463
464
465
466
467
# File 'lib/mongo/server.rb', line 463

def matches_tag_set?(tag_set)
  tag_set.keys.all? do |k|
    tags[k] && tags[k] == tag_set[k]
  end
end

#next_connection_idObject

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.

Since:

  • 2.0.0



688
689
690
# File 'lib/mongo/server.rb', line 688

def next_connection_id
  @connection_id_gen.next_id
end

#poolMongo::Server::ConnectionPool

Get the connection pool for this server.

Examples:

Get the connection pool for the server.

server.pool

Since:

  • 2.0.0



426
427
428
429
430
431
432
433
434
435
436
437
# File 'lib/mongo/server.rb', line 426

def pool
  if unknown?
    raise Error::ServerNotUsable, address
  end

  @pool_lock.synchronize do
    opts = connected? ? options : options.merge(populator_io: false)
    @pool ||= ConnectionPool.new(self, opts).tap do |pool|
      pool.ready
    end
  end
end

#pool_internalServer::ConnectionPool | nil

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.

Internal driver method to retrieve the connection pool for this server.

Unlike pool, pool_internal will not create a pool if one does not already exist.

Since:

  • 2.0.0



447
448
449
450
451
# File 'lib/mongo/server.rb', line 447

def pool_internal
  @pool_lock.synchronize do
    @pool
  end
end

#publish_opening_eventObject

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.

Publishes the server opening event.

Since:

  • 2.0.0



342
343
344
345
346
347
# File 'lib/mongo/server.rb', line 342

def publish_opening_event
  publish_sdam_event(
    Monitoring::SERVER_OPENING,
    Monitoring::Event::ServerOpening.new(address, cluster.topology)
  )
end

#reconnect!true

Restart the server monitor.

Examples:

Restart the server monitor.

server.reconnect!

Since:

  • 2.1.0



477
478
479
480
481
482
# File 'lib/mongo/server.rb', line 477

def reconnect!
  if options[:monitoring_io] != false
    monitor.restart!
  end
  @connected = true
end

#retry_reads?Boolean

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.

Whether the server supports modern read retries.

Since:

  • 2.0.0



549
550
551
# File 'lib/mongo/server.rb', line 549

def retry_reads?
  !!(features.sessions_enabled? && logical_session_timeout)
end

#retry_writes?true, false

Note:

Retryable writes are only available on server versions 3.6+ and with sharded clusters or replica sets.

Note:

Some of the conditions in this method automatically return false for for load balanced topologies. The conditions in this method should always be true, since load-balanced topologies are only available on MongoDB 5.0+, and not for standalone topologies. Therefore, we can assume that retry writes are enabled.

Will writes sent to this server be retried.

Examples:

Will writes be retried.

server.retry_writes?

Since:

  • 2.5.0



570
571
572
# File 'lib/mongo/server.rb', line 570

def retry_writes?
  !!(features.sessions_enabled? && logical_session_timeout && !standalone?) || load_balancer?
end

#start_monitoringObject

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.

Start monitoring the server.

Used internally by the driver to add a server to a cluster while delaying monitoring until the server is in the cluster.

Since:

  • 2.0.0



332
333
334
335
336
337
# File 'lib/mongo/server.rb', line 332

def start_monitoring
  publish_opening_event
  if options[:monitoring_io] != false
    monitor.run!
  end
end

#statusString

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 String representing server status (e.g. PRIMARY).

Since:

  • 2.0.0



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/mongo/server.rb', line 364

def status
  case
  when load_balancer?
    'LB'
  when primary?
    'PRIMARY'
  when secondary?
    'SECONDARY'
  when standalone?
    'STANDALONE'
  when arbiter?
    'ARBITER'
  when ghost?
    'GHOST'
  when other?
    'OTHER'
  when mongos?
    'MONGOS'
  when unknown?
    'UNKNOWN'
  else
    # Since the summary method is often used for debugging, do not raise
    # an exception in case none of the expected types matched
    nil
  end
end

#summaryObject

Note:

This method is experimental and subject to change.

Since:

  • 2.7.0



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/mongo/server.rb', line 395

def summary
  status = self.status || ''
  if replica_set_name
    status += " replica_set=#{replica_set_name}"
  end

  unless monitor&.running?
    status += " NO-MONITORING"
  end

  if @pool
    status += " pool=#{@pool.summary}"
  end

  address_bit = if address
    "#{address.host}:#{address.port}"
  else
    'nil'
  end

  "#<Server address=#{address_bit} #{status}>"
end

#unknown!(options = {}) ⇒ Object

Marks server unknown and publishes the associated SDAM event (server description changed).

If the generation is passed in options, the server will only be marked unknown if the passed generation is no older than the current generation of the server’s connection pool.

Options Hash (options):

  • :generation (Integer)

    Connection pool generation of the connection that was used for the operation that produced the error.

  • :keep_connection_pool (true | false)

    Usually when the new server description is unknown, the connection pool on the respective server is cleared. Set this option to true to keep the existing connection pool (required when handling not master errors on 4.2+ servers).

  • :topology_version (TopologyVersion)

    Topology version of the error response that is causing the server to be marked unknown.

  • :stop_push_monitor (true | false)

    Whether to stop the PushMonitor associated with the server, if any.

  • :service_id (Object)

    Discard state for the specified service id only.

Since:

  • 2.4.0, SDAM events are sent as of version 2.7.0



598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
# File 'lib/mongo/server.rb', line 598

def unknown!(options = {})
  pool = pool_internal

  if load_balancer?
    # When the client is in load-balanced topology, servers (the one and
    # only that can be) starts out as a load balancer and stays as a
    # load balancer indefinitely. As such it is not marked unknown.
    #
    # However, this method also clears connection pool for the server
    # when the latter is marked unknown, and this part needs to happen
    # when the server is a load balancer.
    #
    # It is possible for a load balancer server to not have a service id,
    # for example if there haven't been any successful connections yet to
    # this server, but the server can still be marked unknown if one
    # of such connections failed midway through its establishment.
    if service_id = options[:service_id]
      pool&.disconnect!(service_id: service_id)
    end
    return
  end

  # NOTE: You cannot use safe navigation here because if pool is nil you end
  # up trying to evaluate Integer < nil which is invalid.
  if options[:generation] && pool && options[:generation] < pool.generation
    return
  end

  if options[:topology_version] && description.topology_version &&
    !options[:topology_version].gt?(description.topology_version)
  then
    return
  end

  if options[:stop_push_monitor]
    monitor&.stop_push_monitor!
  end

  # SDAM flow will update description on the server without in-place
  # mutations and invoke SDAM transitions as needed.
  config = {}
  if options[:service_id]
    config['serviceId'] = options[:service_id]
  end
  if options[:topology_version]
    config['topologyVersion'] = options[:topology_version]
  end
  new_description = Description.new(address, config,
    load_balancer: load_balancer?,
    force_load_balancer: options[:connect] == :load_balanced,
  )
  cluster.run_sdam_flow(description, new_description, options)
end

#update_description(description) ⇒ 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.

Since:

  • 2.0.0



653
654
655
656
657
658
659
# File 'lib/mongo/server.rb', line 653

def update_description(description)
  pool = pool_internal
  if pool && !description.unknown?
    pool.ready
  end
  @description = description
end

#update_last_scanObject

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.

Since:

  • 2.0.0



693
694
695
696
# File 'lib/mongo/server.rb', line 693

def update_last_scan
  @last_scan = Time.now
  @last_scan_monotime = Utils.monotonic_time
end

#with_connection(connection_global_id: nil, context: nil, &block) ⇒ Object

Execute a block of code with a connection, that is checked out of the server’s pool and then checked back in.

Examples:

Send a message with the connection.

server.with_connection do |connection|
  connection.dispatch([ command ])
end

Since:

  • 2.3.0



495
496
497
498
499
500
501
# File 'lib/mongo/server.rb', line 495

def with_connection(connection_global_id: nil, context: nil, &block)
  pool.with_connection(
    connection_global_id: connection_global_id,
    context: context,
    &block
  )
end