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 deprioritized on overload errors only when enableOverloadRetargeting is enabled.

Since:

  • 2.1.0

[ GitHub ]

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

def deprioritize_server?(cluster, error)
  return true if cluster.sharded? || cluster.load_balanced?
  return false unless client.options[:enable_overload_retargeting]

  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 86

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 49

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 117

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

  error_count = 0
  loop do
    result = yield

    return result
  rescue Error::TimeoutError
    raise
  rescue Error::OperationFailure::Family => e
    raise e unless e.label?('SystemOverloadedError') && e.label?('RetryableError')

    error_count += 1
    policy = client.retry_policy
    delay = policy.backoff_delay(error_count)
    raise e unless policy.should_retry_overload?(error_count, delay, context: context)

    Logger.logger.warn("Overload retry due to: #{e.class.name}: #{e.message}")
    sleep(delay)
  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 96

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