class Mongo::Server::Connection

This class models the socket connections for servers and their behavior.

@since 2.0.0

Constants

PING

The ping command.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_BYTES

The ping message as raw bytes.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_MESSAGE

Ping message.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG

The ping command for an OP_MSG (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG_BYTES

The ping OP_MSG message as raw bytes (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

PING_OP_MSG_MESSAGE

Ping message as an OP_MSG (server versions >= 3.6).

@since 2.5.0

@deprecated No longer necessary with Server Selection specification.

Attributes

global_id[R]

@return [ Integer ] The global ID for the connection. This will be unique across all connections.

id[R]

@return [ Integer ] The ID for the connection. This will be unique across connections to the same server object.

@since 2.9.0

last_checkin[R]

@return [ Time ] The last time the connection was checked back into a pool.

@since 2.5.0

Public Class Methods

new(server, options = {}) click to toggle source

Creates a new connection object to the specified target address with the specified options.

The constructor does not perform any I/O (and thus does not create sockets, handshakes nor authenticates); call connect! method on the connection object to create the network connection.

@api private

@example Create the connection.

Connection.new(server)

@note Connection must never be directly instantiated outside of a

Server.

@param [ Mongo::Server ] server The server the connection is for. @param [ Hash ] options The connection options.

@option options :pipe [ IO ] The file descriptor for the read end of the

pipe to listen on during the select system call when reading from the
socket.

@option options [ Integer ] :generation The generation of this

connection. The generation should only be specified in this option
when not in load-balancing mode, and it should be the generation
of the connection pool when the connection is created. In
load-balancing mode, the generation is set on the connection
after the handshake completes.

@option options [ Hash ] :server_api The requested server API version.

This hash can have the following items:
- *:version* -- string
- *:strict* -- boolean
- *:deprecation_errors* -- boolean

@since 2.0.0

# File lib/mongo/server/connection.rb, line 106
def initialize(server, options = {})
  if server.load_balancer? && options[:generation]
    raise ArgumentError, "Generation cannot be set when server is a load balancer"
  end

  @id = server.next_connection_id
  @global_id = self.class.next_id
  @monitoring = server.monitoring
  @options = options.freeze
  @server = server
  @socket = nil
  @last_checkin = nil
  @auth_mechanism = nil
  @pid = Process.pid
  @pinned = false

  publish_cmap_event(
    Monitoring::Event::Cmap::ConnectionCreated.new(address, id)
  )
end

Public Instance Methods

closed?() click to toggle source

Whether the connection was closed.

Closed connections should no longer be used. Instead obtain a new connection from the connection pool.

@return [ true | false ] Whether connection was closed.

@since 2.9.0

# File lib/mongo/server/connection.rb, line 166
def closed?
  !!@closed
end
connect!() click to toggle source

Establishes a network connection to the target address.

If the connection is already established, this method does nothing.

@example Connect to the host.

connection.connect!

@note This method mutates the connection object by setting a socket if

one previously did not exist.

@return [ true ] If the connection succeeded.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 229
def connect!
  raise_if_closed!

  unless @socket
    @socket = create_socket
    @description, @compressor = do_connect

    if server.load_balancer?
      if Lint.enabled?
        unless service_id
          raise Error::InternalDriverError, "The connection is to a load balancer and it must have service_id set here, but does not"
        end
      end
      @generation = connection_pool.generation_manager.generation(service_id: service_id)
    end

    publish_cmap_event(
      Monitoring::Event::Cmap::ConnectionReady.new(address, id)
    )

    @close_event_published = false
  end
  true
end
connected?() click to toggle source

Whether the connection was connected and was not interrupted, closed, or had an error raised.

@return [ true | false ] if the connection was connected.

# File lib/mongo/server/connection.rb, line 154
def connected?
  !closed? && !error? && !interrupted? && !!@socket
end
connection_pool() click to toggle source

The connection pool from which this connection was created. May be nil.

@api private

# File lib/mongo/server/connection.rb, line 146
def connection_pool
  options[:connection_pool]
end
disconnect!(options = nil) click to toggle source

Disconnect the connection.

@note Once a connection is disconnected, it should no longer be used.

A new connection should be obtained from the connection pool which
will either return a ready connection or create a new connection.
If linting is enabled, reusing a disconnected connection will raise
Error::LintError. If linting is not enabled, a warning will be logged.

@note This method mutates the connection object by setting the socket

to nil if the closing succeeded.

@option options [ Symbol ] :reason The reason why the connection is

being closed.

@option options [ true | false ] :interrupted Whether or not the

connection was interrupted.

@return [ true ] If the disconnect succeeded.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 305
def disconnect!(options = nil)
  # Note: @closed may be true here but we also may have a socket.
  # Check the socket and not @closed flag.
  @auth_mechanism = nil
  @last_checkin = nil
  if socket
    socket.close rescue nil
    @socket = nil
  end
  @closed = true
  interrupted! if options && options[:interrupted]

  # To satisfy CMAP spec tests, publish close events even if the
  # socket was never connected (and thus the ready event was never
  # published). But track whether we published close event and do not
  # publish it multiple times, unless the socket was reconnected -
  # in that case publish the close event once per socket close.
  unless @close_event_published
    reason = options && options[:reason]
    publish_cmap_event(
      Monitoring::Event::Cmap::ConnectionClosed.new(
        address,
        id,
        reason,
      ),
    )
    @close_event_published = true
  end

  true
end
error?() click to toggle source

@api private

# File lib/mongo/server/connection.rb, line 186
def error?
  !!@error
end
interrupted!() click to toggle source

Mark the connection as interrupted.

# File lib/mongo/server/connection.rb, line 181
def interrupted!
  @interrupted = true
end
interrupted?() click to toggle source

Whether the connection was interrupted.

Interrupted connections were already removed from the pool and should not be checked back into the pool.

@return [ true | false ] Whether connection was interrupted.

# File lib/mongo/server/connection.rb, line 176
def interrupted?
  !!@interrupted
end
pin() click to toggle source

Mark the connection as pinned.

@api private

# File lib/mongo/server/connection.rb, line 205
def pin
  @pinned = true
end
ping() click to toggle source

Ping the connection to see if the server is responding to commands. This is non-blocking on the server side.

@example Ping the connection.

connection.ping

@note This uses a pre-serialized ping message for optimization.

@return [ true, false ] If the server is accepting connections.

@since 2.1.0

@deprecated No longer necessary with Server Selection specification.

# File lib/mongo/server/connection.rb, line 350
def ping
  bytes = features.op_msg_enabled? ? PING_OP_MSG_BYTES : PING_BYTES
  ensure_connected do |socket|
    reply = add_server_diagnostics do
      socket.write(bytes)
      Protocol::Message.deserialize(socket, max_message_size)
    end
    reply.documents[0][Operation::Result::OK] == 1
  end
end
pinned?() click to toggle source

Whether the connection is used by a transaction or cursor operations.

Pinned connections should not be disconnected and removed from a connection pool if they are idle or stale.

# @return [ true | false ] Whether connection is pinned.

@api private

# File lib/mongo/server/connection.rb, line 198
def pinned?
  @pinned
end
record_checkin!() click to toggle source

Record the last checkin time.

@example Record the checkin time on this connection.

connection.record_checkin!

@return [ self ]

@since 2.5.0

# File lib/mongo/server/connection.rb, line 380
def record_checkin!
  @last_checkin = Time.now
  self
end
socket_timeout() click to toggle source

Get the timeout to execute an operation on a socket.

@return [ Float ] The operation timeout in seconds.

@since 2.0.0

# File lib/mongo/server/connection.rb, line 366
def socket_timeout
  @timeout ||= options[:socket_timeout]
end
Also aliased as: timeout
timeout()

@deprecated Please use :socket_timeout instead. Will be removed in 3.0.0

Alias for: socket_timeout
unpin() click to toggle source

Mark the connection as not pinned.

@api private

# File lib/mongo/server/connection.rb, line 212
def unpin
  @pinned = false
end

Private Instance Methods

create_socket() click to toggle source

Creates the socket. The method is separate from do_connect, so that pending connections can be closed if they are interrupted during hello.

@return [ Socket ] The created socket.

# File lib/mongo/server/connection.rb, line 259
        def create_socket
  add_server_diagnostics do
    address.socket(socket_timeout, ssl_options.merge(
      connection_address: address, connection_generation: generation, pipe: options[:pipe]))
  end
end
deliver(message, client, options = {}) click to toggle source
Calls superclass method
# File lib/mongo/server/connection.rb, line 387
def deliver(message, client, options = {})
  handle_errors do
    super
  end
end
do_connect() click to toggle source

Separate method to permit easier mocking in the test suite.

@return [ Array<Server::Description, String | Symbol> ] A server

description instance from the hello response of the returned socket
and the compressor to use.
# File lib/mongo/server/connection.rb, line 271
        def do_connect
  raise_if_closed!
  begin
    pending_connection = PendingConnection.new(
      socket, @server, monitoring, options.merge(id: id))
    pending_connection.handshake_and_authenticate!
  rescue Exception
    socket&.close
    @socket = nil
    raise
  end

  [pending_connection.description, pending_connection.compressor]
end
handle_errors() { || ... } click to toggle source
# File lib/mongo/server/connection.rb, line 393
def handle_errors
  begin
    yield
  rescue Error::SocketError => e
    @error = e
    @server.unknown!(
      generation: e.generation,
      # or description.service_id?
      service_id: e.service_id,
      stop_push_monitor: true,
    )
    raise
  rescue Error::SocketTimeoutError => e
    @error = e
    raise
  end
end
raise_if_closed!() click to toggle source
# File lib/mongo/server/connection.rb, line 411
def raise_if_closed!
  if error?
    raise Error::ConnectionPerished, "Connection #{generation}:#{id} for #{address.seed} is perished. Reconnecting closed or errored connections is no longer supported"
  end

  if closed?
    raise Error::ConnectionPerished, "Connection #{generation}:#{id} for #{address.seed} is closed. Reconnecting closed or errored connections is no longer supported"
  end
end