Class: Mongo::Retryable::ReadWorker Private
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
BaseWorker ,
Forwardable
|
|
Instance Chain:
self,
BaseWorker
|
|
Inherits: |
Mongo::Retryable::BaseWorker
|
Defined in: | lib/mongo/retryable/read_worker.rb |
Overview
Implements the logic around retrying read operations.
Class Method Summary
BaseWorker
- Inherited
.new | Constructs a new worker. |
Instance Attribute Summary
BaseWorker
- Inherited
Instance Method Summary
-
#read_with_one_retry(options = nil) { ... } ⇒ Result
Internal use only
Execute a read operation with a single retry on network errors.
-
#read_with_retry(session = nil, server_selector = nil, context = nil, &block) ⇒ Result
Internal use only
Execute a read operation with retrying.
-
#read_with_retry_cursor(session, server_selector, view, context: nil, &block) ⇒ Cursor
Internal use only
Execute a read operation returning a cursor with retrying.
-
#deprecated_legacy_read_with_retry(&block) ⇒ Result
private
Internal use only
Attempts to do a legacy read_with_retry, without either a session or server_selector.
-
#legacy_read_with_retry(session, server_selector, context = nil, &block) ⇒ Result
private
Internal use only
Attempts to do a “legacy” read with retry.
-
#modern_read_with_retry(session, server_selector, context, &block) ⇒ Result
private
Internal use only
Attempts to do a “modern” read with retry.
-
#read_without_retry(session, server_selector, &block) ⇒ Result
private
Internal use only
Attempts to do a read without a retry; for example, when retries have been explicitly disabled.
-
#retry_read(original_error, session, server_selector, context: nil, failed_server: nil, &block) ⇒ Result
private
Internal use only
The retry logic of the “modern” read_with_retry implementation.
- #select_server_for_retry(original_error, session, server_selector, context, failed_server) private Internal use only
BaseWorker
- Inherited
#deprecation_warning | Logs the given deprecation warning the first time it is called for a given key; after that, it does nothing when given the same key. |
#is_legacy_retryable_exception? | Tests to see if the given exception instance is of a type that can be retried with legacy retry mechanism. |
#is_retryable_exception? | Tests to see if the given exception instance is of a type that can be retried with modern retry mechanism. |
#legacy_retryable_exceptions | Indicate which exception classes that are generally retryable when using legacy retries mechanism. |
#log_retry | Log a warning so that any application slow down is immediately obvious. |
#retryable_exceptions | Indicate which exception classes that are generally retryable when using modern retries mechanism. |
Instance Method Details
#deprecated_legacy_read_with_retry(&block) ⇒ Result
(private)
Attempts to do a legacy read_with_retry, without either a session or server_selector. This is a deprecated use-case, and a warning will be issued the first time this is invoked.
# File 'lib/mongo/retryable/read_worker.rb', line 172
def deprecated_legacy_read_with_retry(&block) deprecation_warning :read_with_retry, 'Legacy read_with_retry invocation - ' \ 'please update the application and/or its dependencies' # Since we don't have a session, we cannot use the modern read retries. # And we need to select a server but we don't have a server selector. # Use PrimaryPreferred which will work as long as there is a data # bearing node in the cluster; the block may select a different server # which is fine. server_selector = ServerSelector.get(mode: :primary_preferred) legacy_read_with_retry(nil, server_selector, &block) end
#legacy_read_with_retry(session, server_selector, context = nil, &block) ⇒ Result
(private)
Attempts to do a “legacy” read with retry. The operation will be attempted multiple times, up to the client’s max_read_retries
setting.
# File 'lib/mongo/retryable/read_worker.rb', line 226
def legacy_read_with_retry(session, server_selector, context = nil, &block) context&.check_timeout! attempt = attempt ? attempt + 1 : 1 yield select_server(cluster, server_selector, session) rescue *legacy_retryable_exceptions, Error::OperationFailure::Family => e e.add_notes('legacy retry', "attempt #{attempt}") if is_legacy_retryable_exception?(e) raise e if attempt > client.max_read_retries || session&.in_transaction? elsif e.retryable? && !session&.in_transaction? raise e if attempt > client.max_read_retries else raise e end log_retry(e, message: 'Legacy read retry') sleep(client.read_retry_interval) unless is_retryable_exception?(e) retry end
#modern_read_with_retry(session, server_selector, context, &block) ⇒ Result
(private)
Attempts to do a “modern” read with retry. Only a single retry will be attempted.
# File 'lib/mongo/retryable/read_worker.rb', line 198
def modern_read_with_retry(session, server_selector, context, &block) server = select_server( cluster, server_selector, session, timeout: context&.remaining_timeout_sec ) yield server rescue *retryable_exceptions, Error::OperationFailure::Family, Auth::Unauthorized, Error::PoolError => e e.add_notes('modern retry', 'attempt 1') raise e if session.in_transaction? raise e if !is_retryable_exception?(e) && !e.write_retryable? retry_read(e, session, server_selector, context: context, failed_server: server, &block) end
#read_with_one_retry(options = nil) { ... } ⇒ Result
This only retries read operations on socket errors.
Execute a read operation with a single retry on network errors.
This method is used by the driver for some of the internal housekeeping operations. Application-requested reads should use read_with_retry rather than this method.
#read_with_retry(session = nil, server_selector = nil, context = nil, &block) ⇒ Result
Execute a read operation with retrying.
This method performs server selection for the specified server selector and yields to the provided block, which should execute the initial query operation and return its result. The block will be passed the server selected for the operation. If the block raises an exception, and this exception corresponds to a read retryable error, and read retries are enabled for the client, this method will perform server selection again and yield to the block again (with potentially a different server). If the block returns successfully, the result of the block is returned.
If modern retry reads are on (which is the default), the initial read operation will be retried once. If legacy retry reads are on, the initial read operation will be retried zero or more times depending on the :max_read_retries
client setting, the default for which is 1. To disable read retries, turn off modern read retries by setting retry_reads: false and set :max_read_retries
to 0 on the client.
# File 'lib/mongo/retryable/read_worker.rb', line 117
def read_with_retry(session = nil, server_selector = nil, context = nil, &block) if session.nil? && server_selector.nil? deprecated_legacy_read_with_retry(&block) elsif session&.retry_reads? modern_read_with_retry(session, server_selector, context, &block) elsif client.max_read_retries > 0 legacy_read_with_retry(session, server_selector, context, &block) else read_without_retry(session, server_selector, &block) end end
#read_with_retry_cursor(session, server_selector, view, context: nil, &block) ⇒ Cursor
Execute a read operation returning a cursor with retrying.
This method performs server selection for the specified server selector and yields to the provided block, which should execute the initial query operation and return its result. The block will be passed the server selected for the operation. If the block raises an exception, and this exception corresponds to a read retryable error, and read retries are enabled for the client, this method will perform server selection again and yield to the block again (with potentially a different server). If the block returns successfully, the result of the block (which should be a Mongo::Operation::Result) is used to construct a ::Mongo::Cursor
object for the result set. The cursor is then returned.
If modern retry reads are on (which is the default), the initial read operation will be retried once. If legacy retry reads are on, the initial read operation will be retried zero or more times depending on the :max_read_retries
client setting, the default for which is 1. To disable read retries, turn off modern read retries by setting retry_reads: false and set :max_read_retries
to 0 on the client.
# File 'lib/mongo/retryable/read_worker.rb', line 68
def read_with_retry_cursor(session, server_selector, view, context: nil, &block) read_with_retry(session, server_selector, context) do |server| result = yield server # RUBY-2367: This will be updated to allow the query cache to # cache cursors with multi-batch results. if QueryCache.enabled? && !view.collection.system_collection? CachingCursor.new(view, result, server, session: session, context: context) else Cursor.new(view, result, server, session: session, context: context) end end end
#read_without_retry(session, server_selector, &block) ⇒ Result
(private)
Attempts to do a read without a retry; for example, when retries have been explicitly disabled.
# File 'lib/mongo/retryable/read_worker.rb', line 256
def read_without_retry(session, server_selector, &block) server = select_server(cluster, server_selector, session) begin yield server rescue *retryable_exceptions, Error::PoolError, Error::OperationFailure::Family => e e.add_note('retries disabled') raise e end end
#retry_read(original_error, session, server_selector, context: nil, failed_server: nil, &block) ⇒ Result
(private)
The retry logic of the “modern” read_with_retry implementation.
# File 'lib/mongo/retryable/read_worker.rb', line 282
def retry_read(original_error, session, server_selector, context: nil, failed_server: nil, &block) server = select_server_for_retry( original_error, session, server_selector, context, failed_server ) log_retry(original_error, message: 'Read retry') begin context&.check_timeout! attempt = attempt ? attempt + 1 : 2 yield server, true rescue Error::TimeoutError raise rescue *retryable_exceptions => e e.add_notes('modern retry', "attempt #{attempt}") if context&.csot? failed_server = server retry else raise e end rescue Error::OperationFailure::Family, Error::PoolError => e e.add_note('modern retry') if e.write_retryable? e.add_note("attempt #{attempt}") if context&.csot? failed_server = server retry else raise e end else original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end rescue Error, Error::AuthError => e e.add_note('modern retry') original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end end
#select_server_for_retry(original_error, session, server_selector, context, failed_server) (private)
# File 'lib/mongo/retryable/read_worker.rb', line 324
def select_server_for_retry(original_error, session, server_selector, context, failed_server) select_server( cluster, server_selector, session, failed_server, timeout: context&.remaining_timeout_sec ) rescue Error, Error::AuthError => e original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end