123456789_123456789_123456789_123456789_123456789_

Module: Mongo::Retryable

Overview

Defines basic behavior around retrying operations.

Since:

  • 2.1.0

Instance Method Summary

Instance Method Details

#deprioritize_server?(cluster, error) ⇒ Boolean (private)

Whether the failed server should be deprioritized during server selection for a retry attempt. For sharded and load-balanced topologies, servers are always deprioritized on any retryable error. For replica sets, servers are only deprioritized when the error carries the SystemOverloadedError label.

Since:

  • 2.1.0

[ GitHub ]

  
# File 'lib/mongo/retryable.rb', line 74

def deprioritize_server?(cluster, error)
  return true if cluster.sharded? || cluster.load_balanced?

  error.respond_to?(:label?) && error.label?('SystemOverloadedError')
end

#read_worker

This method is for internal use only.
Note:

this is only a public method so that tests can add expectations based on it.

Returns the read worker for handling retryable reads.

Since:

  • 2.1.0

[ GitHub ]

  
# File 'lib/mongo/retryable.rb', line 88

def read_worker
  @read_worker ||= ReadWorker.new(self)
end

#select_server(cluster, server_selector, session, failed_server = nil, error: nil, timeout: nil) ⇒ Mongo::Server

This method is for internal use only.

This is a separate method to make it possible for the test suite to assert that server selection is performed during retry attempts.

This is a public method so that it can be accessed via the read and write worker delegates, as needed.

Returns:

Since:

  • 2.1.0

[ GitHub ]

  
# File 'lib/mongo/retryable.rb', line 52

def select_server(cluster, server_selector, session, failed_server = nil, error: nil, timeout: nil)
  deprioritized = if failed_server && deprioritize_server?(cluster, error)
    [failed_server]
  else
    []
  end
  server_selector.select_server(
    cluster,
    nil,
    session,
    deprioritized: deprioritized,
    timeout: timeout
  )
end

#with_overload_retry(context: nil, retry_enabled: true) ⇒ Object

This method is for internal use only.

Wraps an operation with overload retry logic. On overload errors (SystemOverloadedError + RetryableError), retries the block with exponential backoff up to MAX_RETRIES times.

The block should include server selection so it is re-done on retry. For cursor operations (getMore), the same server is reused since the cursor is pinned.

Parameters:

  • context (Operation::Context | nil)

    The operation context for CSOT deadline checking.

  • retry_enabled (true | false)

    Whether overload retries are permitted. When false, overload errors are raised immediately without retrying (used when retryReads/retryWrites is disabled).

Returns:

  • (Object)

    The result of the block.

Since:

  • 2.1.0

[ GitHub ]

  
# File 'lib/mongo/retryable.rb', line 119

def with_overload_retry(context: nil, retry_enabled: true)
  return yield unless retry_enabled

  error_count = 0
  loop do
    begin
      result = yield
      client.retry_policy.record_success(is_retry: error_count > 0)
      return result
    rescue Error::TimeoutError
      raise
    rescue Error::OperationFailure::Family => e
      if e.label?('SystemOverloadedError') && e.label?('RetryableError')
        error_count += 1
        policy = client.retry_policy
        delay = policy.backoff_delay(error_count)
        unless policy.should_retry_overload?(error_count, delay, context: context)
          raise e
        end
        Logger.logger.warn("Overload retry due to: #{e.class.name}: #{e.message}")
        sleep(delay)
      else
        raise e
      end
    end
  end
end

#write_worker

This method is for internal use only.
Note:

this is only a public method so that tests can add expectations based on it.

Returns the write worker for handling retryable writes.

Since:

  • 2.1.0

[ GitHub ]

  
# File 'lib/mongo/retryable.rb', line 98

def write_worker
  @write_worker ||= WriteWorker.new(self)
end