diff --git a/lib/mongo/client.rb b/lib/mongo/client.rb index 5cef5ffea8..b93f837755 100644 --- a/lib/mongo/client.rb +++ b/lib/mongo/client.rb @@ -34,6 +34,7 @@ class Client :write, :write_concern, :retry_reads, :max_read_retries, :read_retry_interval, :retry_writes, :max_write_retries, + :max_adaptive_retries, :enable_overload_retargeting, :timeout_ms, # Options which cannot currently be here: @@ -52,7 +53,6 @@ class Client # # @since 2.1.2 VALID_OPTIONS = %i[ - adaptive_retries app_name auth_mech auth_mech_properties @@ -62,6 +62,7 @@ class Client cleanup compressors direct_connection + enable_overload_retargeting connect connect_timeout database @@ -71,6 +72,7 @@ class Client local_threshold logger log_prefix + max_adaptive_retries max_connecting max_idle_time max_pool_size @@ -587,7 +589,7 @@ def initialize(addresses_or_uri, options = nil) @connect_lock = Mutex.new @retry_policy = Retryable::RetryPolicy.new( - adaptive_retries: !!@options[:adaptive_retries] + max_retries: @options[:max_adaptive_retries] || Retryable::Backpressure::DEFAULT_MAX_RETRIES ) @connect_lock.synchronize do @cluster = Cluster.new( diff --git a/lib/mongo/retryable.rb b/lib/mongo/retryable.rb index dffc1ca776..3cfa383808 100644 --- a/lib/mongo/retryable.rb +++ b/lib/mongo/retryable.rb @@ -15,7 +15,6 @@ # limitations under the License. require 'mongo/retryable/backpressure' -require 'mongo/retryable/token_bucket' require 'mongo/retryable/retry_policy' require 'mongo/retryable/read_worker' require 'mongo/retryable/write_worker' @@ -67,10 +66,11 @@ def select_server(cluster, server_selector, session, failed_server = nil, error: # 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. + # For replica sets, servers are deprioritized on overload errors only + # when enableOverloadRetargeting is enabled. 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 @@ -120,7 +120,7 @@ def with_overload_retry(context: nil, retry_enabled: true) error_count = 0 loop do result = yield - client.retry_policy.record_success(is_retry: error_count > 0) + return result rescue Error::TimeoutError raise diff --git a/lib/mongo/retryable/backpressure.rb b/lib/mongo/retryable/backpressure.rb index fba9485e6b..c36b4273aa 100644 --- a/lib/mongo/retryable/backpressure.rb +++ b/lib/mongo/retryable/backpressure.rb @@ -13,14 +13,8 @@ module Backpressure # Maximum backoff delay in seconds. MAX_BACKOFF = 10 - # Maximum number of retries for overload errors. - MAX_RETRIES = 5 - - # Rate at which tokens are returned to the bucket on success. - RETRY_TOKEN_RETURN_RATE = 0.1 - - # Default capacity of the retry token bucket. - DEFAULT_RETRY_TOKEN_CAPACITY = 1000 + # Default maximum number of retries for overload errors. + DEFAULT_MAX_RETRIES = 2 # Calculate the backoff delay for a given retry attempt. # diff --git a/lib/mongo/retryable/read_worker.rb b/lib/mongo/retryable/read_worker.rb index cebbc23bf8..325e0b818b 100644 --- a/lib/mongo/retryable/read_worker.rb +++ b/lib/mongo/retryable/read_worker.rb @@ -200,9 +200,7 @@ def modern_read_with_retry(session, server_selector, context, &block) session, timeout: context&.remaining_timeout_sec ) - result = yield server - retry_policy.record_success(is_retry: false) - result + 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? && !retryable_overload_error?(e) @@ -295,9 +293,7 @@ def retry_read(original_error, session, server_selector, context: nil, failed_se begin context&.check_timeout! attempt = attempt ? attempt + 1 : 2 - result = yield server, true - retry_policy.record_success(is_retry: true) - result + yield server, true rescue Error::TimeoutError raise rescue *retryable_exceptions => e @@ -358,7 +354,6 @@ def overload_read_retry(last_error, session, server_selector, context, failed_se begin context&.check_timeout! result = yield server, true - retry_policy.record_success(is_retry: true) return result rescue Error::TimeoutError raise @@ -368,7 +363,6 @@ def overload_read_retry(last_error, session, server_selector, context, failed_se is_overload = retryable_overload_error?(e) raise e unless is_overload || is_retryable_exception?(e) || e.write_retryable? - retry_policy.record_non_overload_retry_failure unless is_overload failed_server = server last_error = e end diff --git a/lib/mongo/retryable/retry_policy.rb b/lib/mongo/retryable/retry_policy.rb index 53022af0cc..a4db6fad03 100644 --- a/lib/mongo/retryable/retry_policy.rb +++ b/lib/mongo/retryable/retry_policy.rb @@ -2,27 +2,25 @@ module Mongo module Retryable - # Encapsulates the retry policy for client backpressure, combining - # exponential backoff with jitter and an optional token bucket for - # adaptive retries. + # Encapsulates the retry policy for client backpressure with + # exponential backoff and jitter. # # One instance is created per Client and shared across all operations # on that client. # # @api private class RetryPolicy + # @return [ Integer ] The maximum number of overload retries. + attr_reader :max_retries + # Create a new retry policy. # - # @param [ true | false ] adaptive_retries Whether the adaptive - # retry token bucket is enabled. - def initialize(adaptive_retries: false) - @token_bucket = adaptive_retries ? TokenBucket.new : nil + # @param [ Integer ] max_retries The maximum number of overload + # retry attempts. Defaults to Backpressure::DEFAULT_MAX_RETRIES. + def initialize(max_retries: Backpressure::DEFAULT_MAX_RETRIES) + @max_retries = max_retries end - # @return [ TokenBucket | nil ] The token bucket, if adaptive - # retries are enabled. - attr_reader :token_bucket - # Calculate the backoff delay for a given retry attempt. # # @param [ Integer ] attempt The retry attempt number (1-indexed). @@ -35,46 +33,21 @@ def backoff_delay(attempt, jitter: rand) # Determine whether an overload retry should be attempted. # - # Checks that the attempt number does not exceed MAX_RETRIES, - # that the backoff delay would not exceed the CSOT deadline (if set), - # and that a token is available (if adaptive retries are enabled). - # # @param [ Integer ] attempt The retry attempt number (1-indexed). # @param [ Float ] delay The backoff delay in seconds. - # @param [ Mongo::CsotTimeoutHolder | nil ] context The operation + # @param [ Mongo::Operation::Context | nil ] context The operation # context (for CSOT deadline checking). # # @return [ true | false ] Whether the retry should proceed. def should_retry_overload?(attempt, delay, context: nil) - return false if attempt > Backpressure::MAX_RETRIES + return false if attempt > @max_retries return false if exceeds_deadline?(delay, context) - return false if @token_bucket && !@token_bucket.consume(1) true end - # Record a successful operation by depositing tokens into the - # bucket. - # - # @param [ true | false ] is_retry Whether the success came from - # a retried attempt. - def record_success(is_retry:) - return unless @token_bucket - - tokens = Backpressure::RETRY_TOKEN_RETURN_RATE - tokens += 1 if is_retry - @token_bucket.deposit(tokens) - end - - # Record a non-overload failure during a retry attempt by - # depositing 1 token. - def record_non_overload_retry_failure - @token_bucket&.deposit(1) - end - private - # Check whether the backoff delay would exceed the CSOT deadline. def exceeds_deadline?(delay, context) return false unless context&.csot? diff --git a/lib/mongo/retryable/token_bucket.rb b/lib/mongo/retryable/token_bucket.rb deleted file mode 100644 index 0785feaa56..0000000000 --- a/lib/mongo/retryable/token_bucket.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Mongo - module Retryable - # A thread-safe token bucket for rate limiting retries during server - # overload. Used by the adaptive retry mechanism. - # - # @api private - class TokenBucket - # Create a new token bucket. - # - # @param [ Float ] capacity The maximum number of tokens the bucket - # can hold. Defaults to Backpressure::DEFAULT_RETRY_TOKEN_CAPACITY. - def initialize(capacity: Backpressure::DEFAULT_RETRY_TOKEN_CAPACITY) - @capacity = capacity.to_f - @tokens = @capacity - @mutex = Mutex.new - end - - # @return [ Float ] The maximum capacity of the bucket. - attr_reader :capacity - - # Return the current number of tokens. - # - # @return [ Float ] The current token count. - def tokens - @mutex.synchronize { @tokens } - end - - # Consume tokens from the bucket. - # - # @param [ Float ] count The number of tokens to consume. - # - # @return [ true | false ] true if the tokens were consumed, - # false if there were insufficient tokens. - def consume(count = 1) - @mutex.synchronize do - if @tokens >= count - @tokens -= count - true - else - false - end - end - end - - # Deposit tokens into the bucket, up to the maximum capacity. - # - # @param [ Float ] count The number of tokens to deposit. - # - # @return [ Float ] The new token count. - def deposit(count) - @mutex.synchronize do - @tokens = [ @capacity, @tokens + count ].min - end - end - end - end -end diff --git a/lib/mongo/retryable/write_worker.rb b/lib/mongo/retryable/write_worker.rb index 7a509f49c9..9d87d271b4 100644 --- a/lib/mongo/retryable/write_worker.rb +++ b/lib/mongo/retryable/write_worker.rb @@ -111,11 +111,9 @@ def nro_write_with_retry(_write_concern, context:, &block) error_count = 0 error_to_raise = nil begin - result = server.with_connection(connection_global_id: context.connection_global_id) do |connection| + server.with_connection(connection_global_id: context.connection_global_id) do |connection| yield connection, nil, context end - retry_policy.record_success(is_retry: error_count > 0) if error_count > 0 - result rescue Error::TimeoutError raise rescue *retryable_exceptions, Error::PoolError, Error::OperationFailure::Family => e @@ -254,7 +252,7 @@ def modern_write_with_retry(session, server, context, &block) connection_succeeded = false was_starting = false - result = server.with_connection( + server.with_connection( connection_global_id: context.connection_global_id, context: context ) do |connection| @@ -268,8 +266,6 @@ def modern_write_with_retry(session, server, context, &block) # it later for the retry as well. yield connection, txn_num, context.dup end - retry_policy.record_success(is_retry: false) - result rescue *retryable_exceptions, Error::PoolError, Auth::Unauthorized, Error::OperationFailure::Family => e e.add_notes('modern retry', 'attempt 1') @@ -344,11 +340,9 @@ def retry_write(original_error, txn_num, context:, failed_server: nil, &block) attempt = attempt ? attempt + 1 : 2 log_retry(original_error, message: 'Write retry') - result = server.with_connection(connection_global_id: context.connection_global_id) do |connection| + server.with_connection(connection_global_id: context.connection_global_id) do |connection| yield(connection, txn_num, context) end - retry_policy.record_success(is_retry: true) - result rescue *retryable_exceptions, Error::PoolError => e if retryable_overload_error?(e) e.add_notes('modern retry', "attempt #{attempt}") @@ -414,7 +408,6 @@ def overload_write_retry(last_error, session, txn_num, context:, failed_server:, result = server.with_connection(connection_global_id: context.connection_global_id) do |connection| yield connection, txn_num, context end - retry_policy.record_success(is_retry: true) return result rescue Error::TimeoutError raise @@ -430,7 +423,6 @@ def overload_write_retry(last_error, session, txn_num, context:, failed_server:, unless e.respond_to?(:label?) && e.label?('NoWritesPerformed') error_to_raise = e end - retry_policy.record_non_overload_retry_failure unless is_overload context = context.with(overload_only_retry: false) unless is_overload failed_server = server last_error = e diff --git a/lib/mongo/session.rb b/lib/mongo/session.rb index d569da50a0..f6c3b856f6 100644 --- a/lib/mongo/session.rb +++ b/lib/mongo/session.rb @@ -461,7 +461,7 @@ def with_transaction(options = nil) overload_error_count = 0 overload_encountered = false - loop do # rubocop:disable Metrics/BlockLength + loop do if transaction_attempt > 0 if overload_encountered delay = @client.retry_policy.backoff_delay(overload_error_count) @@ -512,7 +512,6 @@ def with_transaction(options = nil) overload_error_count += 1 elsif overload_encountered overload_error_count += 1 - @client.retry_policy.record_non_overload_retry_failure end next end @@ -553,7 +552,6 @@ def with_transaction(options = nil) overload_error_count += 1 elsif overload_encountered overload_error_count += 1 - @client.retry_policy.record_non_overload_retry_failure end if overload_encountered @@ -590,7 +588,6 @@ def with_transaction(options = nil) overload_error_count += 1 elsif overload_encountered overload_error_count += 1 - @client.retry_policy.record_non_overload_retry_failure end @state = NO_TRANSACTION_STATE next diff --git a/lib/mongo/uri/options_mapper.rb b/lib/mongo/uri/options_mapper.rb index 4e0fae9396..99838b844d 100644 --- a/lib/mongo/uri/options_mapper.rb +++ b/lib/mongo/uri/options_mapper.rb @@ -304,7 +304,8 @@ def self.uri_option(uri_key, name, **extra) uri_option 'readConcernLevel', :level, group: :read_concern, type: :symbol uri_option 'retryReads', :retry_reads, type: :bool uri_option 'retryWrites', :retry_writes, type: :bool - uri_option 'adaptiveRetries', :adaptive_retries, type: :bool + uri_option 'enableOverloadRetargeting', :enable_overload_retargeting, type: :bool + uri_option 'maxAdaptiveRetries', :max_adaptive_retries, type: :integer uri_option 'zlibCompressionLevel', :zlib_compression_level, type: :zlib_compression_level # Monitoring Options diff --git a/spec/integration/retryable_reads_errors_spec.rb b/spec/integration/retryable_reads_errors_spec.rb index 7e8a1fbe40..e335f37cd3 100644 --- a/spec/integration/retryable_reads_errors_spec.rb +++ b/spec/integration/retryable_reads_errors_spec.rb @@ -297,7 +297,8 @@ let(:client) do authorized_client.with( retry_reads: true, - read: { mode: :primary_preferred } + read: { mode: :primary_preferred }, + enable_overload_retargeting: true ) end diff --git a/spec/mongo/retryable/adaptive_retries_option_spec.rb b/spec/mongo/retryable/adaptive_retries_option_spec.rb deleted file mode 100644 index 3b9a270f62..0000000000 --- a/spec/mongo/retryable/adaptive_retries_option_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe 'adaptiveRetries option' do - describe 'client option' do - it 'defaults to nil (not set)' do - client = new_local_client_nmio([ 'localhost:27017' ]) - expect(client.options[:adaptive_retries]).to be_nil - end - - it 'can be set to true' do - client = new_local_client_nmio([ 'localhost:27017' ], adaptive_retries: true) - expect(client.options[:adaptive_retries]).to be true - end - - it 'can be set to false' do - client = new_local_client_nmio([ 'localhost:27017' ], adaptive_retries: false) - expect(client.options[:adaptive_retries]).to be false - end - end - - describe 'URI option' do - it 'parses adaptiveRetries=true' do - client = new_local_client_nmio('mongodb://localhost:27017/?adaptiveRetries=true') - expect(client.options[:adaptive_retries]).to be true - end - - it 'parses adaptiveRetries=false' do - client = new_local_client_nmio('mongodb://localhost:27017/?adaptiveRetries=false') - expect(client.options[:adaptive_retries]).to be false - end - end -end diff --git a/spec/mongo/retryable/backpressure_options_spec.rb b/spec/mongo/retryable/backpressure_options_spec.rb new file mode 100644 index 0000000000..93a4a7d6ad --- /dev/null +++ b/spec/mongo/retryable/backpressure_options_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Client backpressure options' do + describe 'maxAdaptiveRetries' do + describe 'client option' do + it 'defaults to nil (uses policy default of 2)' do + client = new_local_client_nmio([ 'localhost:27017' ]) + expect(client.options[:max_adaptive_retries]).to be_nil + end + + it 'can be set to an integer' do + client = new_local_client_nmio([ 'localhost:27017' ], max_adaptive_retries: 5) + expect(client.options[:max_adaptive_retries]).to eq(5) + end + + it 'can be set to 0' do + client = new_local_client_nmio([ 'localhost:27017' ], max_adaptive_retries: 0) + expect(client.options[:max_adaptive_retries]).to eq(0) + end + end + + describe 'URI option' do + it 'parses maxAdaptiveRetries=3' do + client = new_local_client_nmio('mongodb://localhost:27017/?maxAdaptiveRetries=3') + expect(client.options[:max_adaptive_retries]).to eq(3) + end + + it 'parses maxAdaptiveRetries=0' do + client = new_local_client_nmio('mongodb://localhost:27017/?maxAdaptiveRetries=0') + expect(client.options[:max_adaptive_retries]).to eq(0) + end + end + + it 'configures the retry policy max_retries' do + client = new_local_client_nmio([ 'localhost:27017' ], max_adaptive_retries: 4) + expect(client.retry_policy.max_retries).to eq(4) + end + end + + describe 'enableOverloadRetargeting' do + describe 'client option' do + it 'defaults to nil (false)' do + client = new_local_client_nmio([ 'localhost:27017' ]) + expect(client.options[:enable_overload_retargeting]).to be_nil + end + + it 'can be set to true' do + client = new_local_client_nmio([ 'localhost:27017' ], enable_overload_retargeting: true) + expect(client.options[:enable_overload_retargeting]).to be true + end + end + + describe 'URI option' do + it 'parses enableOverloadRetargeting=true' do + client = new_local_client_nmio('mongodb://localhost:27017/?enableOverloadRetargeting=true') + expect(client.options[:enable_overload_retargeting]).to be true + end + + it 'parses enableOverloadRetargeting=false' do + client = new_local_client_nmio('mongodb://localhost:27017/?enableOverloadRetargeting=false') + expect(client.options[:enable_overload_retargeting]).to be false + end + end + end +end diff --git a/spec/mongo/retryable/backpressure_spec.rb b/spec/mongo/retryable/backpressure_spec.rb index e9255f4b4f..c8333058a5 100644 --- a/spec/mongo/retryable/backpressure_spec.rb +++ b/spec/mongo/retryable/backpressure_spec.rb @@ -12,16 +12,8 @@ expect(described_class::MAX_BACKOFF).to eq(10) end - it 'defines MAX_RETRIES as 5' do - expect(described_class::MAX_RETRIES).to eq(5) - end - - it 'defines RETRY_TOKEN_RETURN_RATE as 0.1' do - expect(described_class::RETRY_TOKEN_RETURN_RATE).to eq(0.1) - end - - it 'defines DEFAULT_RETRY_TOKEN_CAPACITY as 1000' do - expect(described_class::DEFAULT_RETRY_TOKEN_CAPACITY).to eq(1000) + it 'defines DEFAULT_MAX_RETRIES as 2' do + expect(described_class::DEFAULT_MAX_RETRIES).to eq(2) end end diff --git a/spec/mongo/retryable/client_backpressure_prose_spec.rb b/spec/mongo/retryable/client_backpressure_prose_spec.rb index e708a3c207..50e82f3d98 100644 --- a/spec/mongo/retryable/client_backpressure_prose_spec.rb +++ b/spec/mongo/retryable/client_backpressure_prose_spec.rb @@ -31,7 +31,6 @@ def make_overload_error(message = 'overloaded') ).tap { |ctx| allow(ctx).to receive(:check_timeout!) } end - # Shared client/retryable/worker setup for read-worker prose tests. shared_context 'with read worker' do let(:retry_policy) { Mongo::Retryable::RetryPolicy.new } @@ -78,35 +77,21 @@ def total_sleep_with_jitter(jitter_value) sleep_args.sum end - it 'with jitter=0 backoff is near-zero; with jitter~1 backoff >= 2.1s' do + it 'with jitter=1 the backoff sum is approximately 0.3s' do no_backoff = total_sleep_with_jitter(0.0) with_backoff = total_sleep_with_jitter(1.0) - expect(with_backoff - no_backoff).to be >= 2.1 + # Sum of 2 backoffs is 0.3 seconds (0.1 + 0.2). + expect((with_backoff - (no_backoff + 0.3)).abs).to be < 0.3 end end # ------------------------------------------------------------------------- - # Test 2: Token Bucket Capacity is Enforced + # Test 3: Overload Errors are Retried DEFAULT_MAX_RETRIES Times # ------------------------------------------------------------------------- - describe 'Test 2: token bucket capacity is enforced' do - it 'starts at DEFAULT_RETRY_TOKEN_CAPACITY and never exceeds it' do - policy = Mongo::Retryable::RetryPolicy.new(adaptive_retries: true) - bucket = policy.token_bucket - capacity = Mongo::Retryable::Backpressure::DEFAULT_RETRY_TOKEN_CAPACITY - - expect(bucket.tokens).to eq(capacity) - policy.record_success(is_retry: false) - expect(bucket.tokens).to be <= capacity - end - end - - # ------------------------------------------------------------------------- - # Test 3: Overload Errors are Retried MAX_RETRIES Times - # ------------------------------------------------------------------------- - describe 'Test 3: overload errors are retried MAX_RETRIES times' do + describe 'Test 3: overload errors are retried DEFAULT_MAX_RETRIES times' do include_context 'with read worker' - it 'attempts the command exactly MAX_RETRIES + 1 times' do + it 'attempts the command exactly DEFAULT_MAX_RETRIES + 1 times' do call_count = 0 expect do worker.read_with_retry(session, server_selector, context) do |_s, _r| @@ -115,25 +100,19 @@ def total_sleep_with_jitter(jitter_value) end end.to raise_error(Mongo::Error::OperationFailure) - expect(call_count).to eq(Mongo::Retryable::Backpressure::MAX_RETRIES + 1) + expect(call_count).to eq(Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES + 1) end end # ------------------------------------------------------------------------- - # Test 4: Adaptive Retries are Limited by Token Bucket Tokens + # Test 4: Overload Errors are Retried maxAdaptiveRetries Times When Configured # ------------------------------------------------------------------------- - describe 'Test 4: adaptive retries are limited by token bucket tokens' do + describe 'Test 4: overload errors are retried maxAdaptiveRetries times when configured' do include_context 'with read worker' - let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(adaptive_retries: true) } - - before do - bucket = retry_policy.token_bucket - bucket.consume(bucket.capacity) - bucket.deposit(2) - end + let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(max_retries: 1) } - it 'retries only as many times as there are tokens (2 tokens -> 3 total attempts)' do + it 'attempts the command exactly maxAdaptiveRetries + 1 times' do call_count = 0 expect do worker.read_with_retry(session, server_selector, context) do |_s, _r| @@ -142,7 +121,7 @@ def total_sleep_with_jitter(jitter_value) end end.to raise_error(Mongo::Error::OperationFailure) - expect(call_count).to eq(3) + expect(call_count).to eq(2) end end end diff --git a/spec/mongo/retryable/read_worker_overload_spec.rb b/spec/mongo/retryable/read_worker_overload_spec.rb index 34c61017e0..26b1181ba5 100644 --- a/spec/mongo/retryable/read_worker_overload_spec.rb +++ b/spec/mongo/retryable/read_worker_overload_spec.rb @@ -60,23 +60,23 @@ def make_retryable_error(message = 'not master') describe '#read_with_retry with overload errors' do context 'when an overload error is raised and then succeeds' do it 'retries with backoff and returns the result' do - expect(worker).to receive(:sleep).at_least(:twice) + expect(worker).to receive(:sleep).at_least(:once) call_count = 0 result = worker.read_with_retry(session, server_selector, context) do |_server, _is_retry| call_count += 1 - raise make_overload_error if call_count <= 3 + raise make_overload_error if call_count <= 2 :success end expect(result).to eq(:success) - expect(call_count).to eq(4) + expect(call_count).to eq(3) end end - context 'when overload errors exceed MAX_RETRIES' do - it 'raises after MAX_RETRIES' do - max = Mongo::Retryable::Backpressure::MAX_RETRIES + context 'when overload errors exceed DEFAULT_MAX_RETRIES' do + it 'raises after DEFAULT_MAX_RETRIES' do + max = Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES call_count = 0 expect do @@ -105,42 +105,5 @@ def make_retryable_error(message = 'not master') expect(call_count).to eq(2) end end - - context 'when adaptive retries are enabled and bucket is drained' do - let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(adaptive_retries: true) } - - it 'raises when the token bucket is empty' do - bucket = retry_policy.token_bucket - bucket.tokens.to_i.times { bucket.consume(1) } - - expect do - worker.read_with_retry(session, server_selector, context) do |_server, _is_retry| - raise make_overload_error - end - end.to raise_error(Mongo::Error::OperationFailure, /overloaded/) - end - end - - context 'when record_success is called on success' do - it 'calls record_success(is_retry: false) on first-attempt success' do - expect(retry_policy).to receive(:record_success).with(is_retry: false) - - worker.read_with_retry(session, server_selector, context) do |_server| - :ok - end - end - - it 'calls record_success(is_retry: true) after a retry succeeds' do - call_count = 0 - expect(retry_policy).to receive(:record_success).with(is_retry: true) - - worker.read_with_retry(session, server_selector, context) do |_server, _is_retry| - call_count += 1 - raise make_overload_error if call_count == 1 - - :ok - end - end - end end end diff --git a/spec/mongo/retryable/retry_policy_spec.rb b/spec/mongo/retryable/retry_policy_spec.rb index d4e4af403e..1ac1cf17a0 100644 --- a/spec/mongo/retryable/retry_policy_spec.rb +++ b/spec/mongo/retryable/retry_policy_spec.rb @@ -4,129 +4,67 @@ describe Mongo::Retryable::RetryPolicy do describe '#initialize' do - context 'without adaptive retries' do - let(:policy) { described_class.new } - - it 'does not create a token bucket' do - expect(policy.token_bucket).to be_nil - end + it 'defaults max_retries to DEFAULT_MAX_RETRIES' do + policy = described_class.new + default = Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES + expect(policy.should_retry_overload?(default, 0.1)).to be true + expect(policy.should_retry_overload?(default + 1, 0.1)).to be false end - context 'with adaptive retries' do - let(:policy) { described_class.new(adaptive_retries: true) } - - it 'creates a token bucket' do - expect(policy.token_bucket).to be_a(Mongo::Retryable::TokenBucket) - end + it 'accepts a custom max_retries' do + policy = described_class.new(max_retries: 5) + expect(policy.should_retry_overload?(5, 0.1)).to be true + expect(policy.should_retry_overload?(6, 0.1)).to be false end - end - describe '#backoff_delay' do - let(:policy) { described_class.new } - - it 'delegates to Backpressure.backoff_delay' do - expect(policy.backoff_delay(1, jitter: 1)).to eq(0.1) - expect(policy.backoff_delay(3, jitter: 1)).to eq(0.4) + it 'accepts max_retries of 0' do + policy = described_class.new(max_retries: 0) + expect(policy.should_retry_overload?(1, 0.1)).to be false end end describe '#should_retry_overload?' do - context 'without adaptive retries' do - let(:policy) { described_class.new } + let(:policy) { described_class.new(max_retries: 2) } - it 'allows retries up to MAX_RETRIES' do - expect(policy.should_retry_overload?(1, 0.1)).to be true - expect(policy.should_retry_overload?(5, 0.1)).to be true - end - - it 'denies retries beyond MAX_RETRIES' do - expect(policy.should_retry_overload?(6, 0.1)).to be false - end + it 'allows retries up to max_retries' do + expect(policy.should_retry_overload?(1, 0.1)).to be true + expect(policy.should_retry_overload?(2, 0.1)).to be true end - context 'with adaptive retries' do - let(:policy) { described_class.new(adaptive_retries: true) } - - it 'consumes a token on each retry' do - bucket = policy.token_bucket - # drain all but 2 tokens - (1000 - 2).times { bucket.consume(1) } - - expect(policy.should_retry_overload?(1, 0.1)).to be true - expect(policy.should_retry_overload?(2, 0.1)).to be true - expect(policy.should_retry_overload?(3, 0.1)).to be false - end + it 'denies retries beyond max_retries' do + expect(policy.should_retry_overload?(3, 0.1)).to be false end context 'with CSOT context' do - let(:policy) { described_class.new } - it 'denies retry when delay would exceed deadline' do - ctx = instance_double(Mongo::Operation::Context, csot?: true, deadline: Mongo::Utils.monotonic_time + 0.01) - expect(policy.should_retry_overload?(1, 100, context: ctx)).to be false + expired = instance_double(Mongo::Operation::Context, + csot?: true, + deadline: Mongo::Utils.monotonic_time - 1) + expect(policy.should_retry_overload?(1, 0.1, context: expired)).to be false end it 'allows retry when delay fits within deadline' do - ctx = instance_double(Mongo::Operation::Context, csot?: true, deadline: Mongo::Utils.monotonic_time + 100) - expect(policy.should_retry_overload?(1, 0.1, context: ctx)).to be true + future = instance_double(Mongo::Operation::Context, + csot?: true, + deadline: Mongo::Utils.monotonic_time + 100) + expect(policy.should_retry_overload?(1, 0.1, context: future)).to be true end it 'allows retry when deadline is zero (unlimited)' do - ctx = instance_double(Mongo::Operation::Context, csot?: true, deadline: 0) - expect(policy.should_retry_overload?(1, 100, context: ctx)).to be true - end - end - end - - describe '#record_success' do - context 'with adaptive retries' do - let(:policy) { described_class.new(adaptive_retries: true) } - - it 'deposits RETRY_TOKEN_RETURN_RATE on first attempt success' do - bucket = policy.token_bucket - bucket.consume(10) - initial = bucket.tokens - policy.record_success(is_retry: false) - expect(bucket.tokens).to eq(initial + 0.1) - end - - it 'deposits RETRY_TOKEN_RETURN_RATE + 1 on retry success' do - bucket = policy.token_bucket - bucket.consume(10) - initial = bucket.tokens - policy.record_success(is_retry: true) - expect(bucket.tokens).to eq(initial + 1.1) - end - end - - context 'without adaptive retries' do - let(:policy) { described_class.new } - - it 'does nothing' do - expect { policy.record_success(is_retry: false) }.not_to raise_error + unlimited = instance_double(Mongo::Operation::Context, + csot?: true, + deadline: 0) + expect(policy.should_retry_overload?(1, 0.1, context: unlimited)).to be true end end end - describe '#record_non_overload_retry_failure' do - context 'with adaptive retries' do - let(:policy) { described_class.new(adaptive_retries: true) } - - it 'deposits 1 token' do - bucket = policy.token_bucket - bucket.consume(10) - initial = bucket.tokens - policy.record_non_overload_retry_failure - expect(bucket.tokens).to eq(initial + 1) - end - end - - context 'without adaptive retries' do - let(:policy) { described_class.new } - - it 'does nothing' do - expect { policy.record_non_overload_retry_failure }.not_to raise_error - end + describe '#backoff_delay' do + it 'delegates to Backpressure.backoff_delay' do + policy = described_class.new + result = policy.backoff_delay(1, jitter: 1.0) + expected = Mongo::Retryable::Backpressure.backoff_delay(1, jitter: 1.0) + expect(result).to eq(expected) end end end diff --git a/spec/mongo/retryable/token_bucket_spec.rb b/spec/mongo/retryable/token_bucket_spec.rb deleted file mode 100644 index 7ddf431b7d..0000000000 --- a/spec/mongo/retryable/token_bucket_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -require 'lite_spec_helper' - -describe Mongo::Retryable::TokenBucket do - describe '#initialize' do - it 'starts full with default capacity' do - bucket = described_class.new - expect(bucket.capacity).to eq(1000) - expect(bucket.tokens).to eq(1000) - end - - it 'starts full with custom capacity' do - bucket = described_class.new(capacity: 10) - expect(bucket.capacity).to eq(10) - expect(bucket.tokens).to eq(10) - end - end - - describe '#consume' do - it 'succeeds when tokens are available' do - bucket = described_class.new(capacity: 5) - expect(bucket.consume(1)).to be true - expect(bucket.tokens).to eq(4) - end - - it 'fails when tokens are insufficient' do - bucket = described_class.new(capacity: 1) - expect(bucket.consume(1)).to be true - expect(bucket.consume(1)).to be false - expect(bucket.tokens).to eq(0) - end - - it 'consumes the specified number of tokens' do - bucket = described_class.new(capacity: 10) - expect(bucket.consume(3)).to be true - expect(bucket.tokens).to eq(7) - end - - it 'defaults to consuming 1 token' do - bucket = described_class.new(capacity: 5) - bucket.consume - expect(bucket.tokens).to eq(4) - end - end - - describe '#deposit' do - it 'adds tokens to the bucket' do - bucket = described_class.new(capacity: 10) - bucket.consume(5) - bucket.deposit(3) - expect(bucket.tokens).to eq(8) - end - - it 'caps at capacity' do - bucket = described_class.new(capacity: 10) - bucket.deposit(5) - expect(bucket.tokens).to eq(10) - end - - it 'caps at capacity after partial consumption' do - bucket = described_class.new(capacity: 10) - bucket.consume(2) - bucket.deposit(5) - expect(bucket.tokens).to eq(10) - end - end - - describe 'thread safety' do - # Use capacity 2000, start at 1000 tokens. - # With 500 consumes and 500 deposits, floor/ceiling cannot be hit: - # min possible = 1000 - 500 = 500 > 0 (all consumes succeed) - # max possible = 1000 + 500 = 1500 < 2000 (all deposits effective) - # So the net change is guaranteed to be 0, making the assertion reliable. - let(:bucket) do - b = described_class.new(capacity: 2000) - b.consume(1000) - b - end - - def run_concurrent_operations(bucket) - threads = [] - 10.times { threads << Thread.new { 50.times { bucket.consume(1) } } } - 5.times { threads << Thread.new { 100.times { bucket.deposit(1) } } } - threads.each(&:join) - end - - it 'handles concurrent consume and deposit' do - run_concurrent_operations(bucket) - expect(bucket.tokens).to eq(1000) - end - end -end diff --git a/spec/mongo/retryable/write_worker_overload_spec.rb b/spec/mongo/retryable/write_worker_overload_spec.rb index 49a2ef3aac..f5b24136c4 100644 --- a/spec/mongo/retryable/write_worker_overload_spec.rb +++ b/spec/mongo/retryable/write_worker_overload_spec.rb @@ -9,7 +9,7 @@ end end - let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(adaptive_retries: false) } + let(:retry_policy) { Mongo::Retryable::RetryPolicy.new } let(:client) do instance_double(Mongo::Client).tap do |c| @@ -94,18 +94,6 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) end describe '#modern_write_with_retry' do - context 'when the operation succeeds on first attempt' do - it 'records success and returns the result' do - expect(retry_policy).to receive(:record_success).with(is_retry: false) - - result = worker.modern_write_with_retry(session, server, context) do |_conn, _txn, _ctx| - :ok - end - - expect(result).to eq(:ok) - end - end - context 'when an overload error occurs' do it 'enters the overload retry loop' do call_count = 0 @@ -161,21 +149,16 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) expect(result).to eq(:write_ok) end - - it 'records success on retry' do - expect(retry_policy).to receive(:record_success).with(is_retry: true) - call_overload_retry(worker) { |_c, _t, _x| :ok } - end end context 'with multiple overload errors' do it 'retries multiple times with backoff' do call_count = 0 - expect(worker).to receive(:sleep).exactly(3).times + expect(worker).to receive(:sleep).twice result = call_overload_retry(worker) do |_c, _t, _x| call_count += 1 - raise make_overload_error if call_count < 3 + raise make_overload_error if call_count < 2 :finally_ok end @@ -184,9 +167,9 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) end end - context 'when MAX_RETRIES (5) is exceeded' do + context 'when DEFAULT_MAX_RETRIES (2) is exceeded' do it 'raises the last error' do - max = Mongo::Retryable::Backpressure::MAX_RETRIES + 1 + max = Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES + 1 expect do call_overload_retry(worker, error_count: max) { |_c, _t, _x| :should_not_reach } @@ -205,7 +188,7 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) end end.to raise_error(Mongo::Error::OperationFailure, /overloaded/) - expect(call_count).to eq(Mongo::Retryable::Backpressure::MAX_RETRIES) + expect(call_count).to eq(Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES) end end @@ -241,9 +224,8 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) end context 'when a non-overload retryable error occurs during overload loop' do - it 'records non-overload failure and continues retrying' do + it 'continues retrying' do call_count = 0 - expect(retry_policy).to receive(:record_non_overload_retry_failure).once result = call_overload_retry(worker) do |_c, _t, _x| call_count += 1 @@ -256,39 +238,4 @@ def call_overload_retry(wkr, error: nil, error_count: 1, &block) end end end - - describe 'record_success on retry_write path' do - it 'records success after standard retry succeeds' do - expect(retry_policy).to receive(:record_success).with(is_retry: true) - call_count = 0 - - worker.modern_write_with_retry(session, server, context) do |_conn, _txn, _ctx| - call_count += 1 - raise make_retryable_write_error if call_count == 1 - - :ok - end - end - end - - describe 'adaptive retries (token bucket)' do - let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(adaptive_retries: true) } - - context 'when the token bucket is exhausted' do - before { retry_policy.token_bucket.consume(retry_policy.token_bucket.capacity) } - - it 'raises the error instead of retrying' do - expect do - call_overload_retry(worker) { |_c, _t, _x| :no } - end.to raise_error(Mongo::Error::OperationFailure, /overloaded/) - end - end - - context 'when there are tokens available' do - it 'retries and records success' do - expect(retry_policy).to receive(:record_success).with(is_retry: true) - call_overload_retry(worker) { |_c, _t, _x| :ok } - end - end - end end diff --git a/spec/mongo/retryable_spec.rb b/spec/mongo/retryable_spec.rb index 3283e4a877..72d1ec59e6 100644 --- a/spec/mongo/retryable_spec.rb +++ b/spec/mongo/retryable_spec.rb @@ -123,6 +123,7 @@ def retry_write_allowed?(*args) allow(client).to receive(:max_read_retries).and_return(max_read_retries) allow(client).to receive(:max_write_retries).and_return(max_write_retries) allow(client).to receive(:retry_policy).and_return(Mongo::Retryable::RetryPolicy.new) + allow(client).to receive(:options).and_return({}) end end diff --git a/spec/mongo/session/with_transaction_overload_spec.rb b/spec/mongo/session/with_transaction_overload_spec.rb index 3b1019db08..99f4a54ec4 100644 --- a/spec/mongo/session/with_transaction_overload_spec.rb +++ b/spec/mongo/session/with_transaction_overload_spec.rb @@ -6,7 +6,7 @@ # this file is under spec/mongo/session/ (not spec/mongo/). describe 'Mongo::Session#with_transaction overload retries' do let(:retry_policy) do - Mongo::Retryable::RetryPolicy.new(adaptive_retries: false) + Mongo::Retryable::RetryPolicy.new end let(:client) do @@ -73,8 +73,6 @@ def make_commit_transient_overload_error method.call(attempt, jitter: 1.0) end - allow(retry_policy).to receive(:record_non_overload_retry_failure).and_call_original - allow(session).to receive(:sleep) end @@ -103,9 +101,9 @@ def make_commit_transient_overload_error end end - context 'when overload errors exceed MAX_RETRIES' do - it 'raises the error after MAX_RETRIES' do - max_retries = Mongo::Retryable::Backpressure::MAX_RETRIES + context 'when overload errors exceed DEFAULT_MAX_RETRIES' do + it 'raises the error after DEFAULT_MAX_RETRIES' do + max_retries = Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES call_count = 0 expect do @@ -125,7 +123,6 @@ def make_commit_transient_overload_error it 'uses overload backoff for the subsequent non-overload error' do expect(retry_policy).to receive(:backoff_delay).twice.and_call_original - expect(retry_policy).to receive(:record_non_overload_retry_failure).once call_count = 0 session.with_transaction do @@ -178,13 +175,13 @@ def make_commit_transient_overload_error end end - context 'when commit overload errors exceed MAX_RETRIES' do + context 'when commit overload errors exceed DEFAULT_MAX_RETRIES' do before do allow(session).to receive(:commit_transaction).and_raise(make_commit_overload_error) end - it 'raises after MAX_RETRIES' do - max_retries = Mongo::Retryable::Backpressure::MAX_RETRIES + it 'raises after DEFAULT_MAX_RETRIES' do + max_retries = Mongo::Retryable::Backpressure::DEFAULT_MAX_RETRIES expect(retry_policy).to receive(:backoff_delay) .exactly(max_retries + 1).times.and_call_original diff --git a/spec/mongo/session/with_transaction_timeout_spec.rb b/spec/mongo/session/with_transaction_timeout_spec.rb index 694a4c6028..c300fb76ca 100644 --- a/spec/mongo/session/with_transaction_timeout_spec.rb +++ b/spec/mongo/session/with_transaction_timeout_spec.rb @@ -11,7 +11,7 @@ # the language allows to expose the underlying error as a cause of a timeout # error." Ruby supports this via Exception#cause. describe 'Mongo::Session#with_transaction timeout enforcement' do - let(:retry_policy) { Mongo::Retryable::RetryPolicy.new(adaptive_retries: false) } + let(:retry_policy) { Mongo::Retryable::RetryPolicy.new } let(:client) do instance_double(Mongo::Client).tap do |c| diff --git a/spec/spec_tests/data/client_backpressure/backpressure-connection-checkin.yml b/spec/spec_tests/data/client_backpressure/backpressure-connection-checkin.yml index 7c4359335c..ce8c1acb36 100644 --- a/spec/spec_tests/data/client_backpressure/backpressure-connection-checkin.yml +++ b/spec/spec_tests/data/client_backpressure/backpressure-connection-checkin.yml @@ -58,10 +58,3 @@ tests: - connectionCheckedInEvent: {} - connectionCheckedOutEvent: {} - connectionCheckedInEvent: {} - - connectionCheckedOutEvent: {} - - connectionCheckedInEvent: {} - - connectionCheckedOutEvent: {} - - connectionCheckedInEvent: {} - - connectionCheckedOutEvent: {} - - connectionCheckedInEvent: {} - diff --git a/spec/spec_tests/data/client_backpressure/backpressure-retry-loop.yml b/spec/spec_tests/data/client_backpressure/backpressure-retry-loop.yml index 5b1f064641..902726f626 100644 --- a/spec/spec_tests/data/client_backpressure/backpressure-retry-loop.yml +++ b/spec/spec_tests/data/client_backpressure/backpressure-retry-loop.yml @@ -92,7 +92,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listDatabases] errorLabels: [RetryableError, SystemOverloadedError] @@ -116,10 +116,6 @@ tests: commandName: listDatabases - commandStartedEvent: commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - commandSucceededEvent: commandName: listDatabases - description: 'client.listDatabases (read) does not retry if retryReads=false' @@ -161,7 +157,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listDatabases] errorLabels: [RetryableError, SystemOverloadedError] @@ -183,10 +179,6 @@ tests: commandName: listDatabases - commandStartedEvent: commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - commandSucceededEvent: commandName: listDatabases - description: 'client.listDatabaseNames (read) does not retry if retryReads=false' @@ -226,7 +218,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -250,10 +242,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'client.createChangeStream (read) does not retry if retryReads=false' @@ -297,7 +285,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [bulkWrite] errorLabels: [RetryableError, SystemOverloadedError] @@ -324,10 +312,6 @@ tests: commandName: bulkWrite - commandStartedEvent: commandName: bulkWrite - - commandFailedEvent: - commandName: bulkWrite - - commandStartedEvent: - commandName: bulkWrite - commandSucceededEvent: commandName: bulkWrite - description: 'client.clientBulkWrite (write) does not retry if retryWrites=false' @@ -374,7 +358,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -398,10 +382,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'database.aggregate (read) does not retry if retryReads=false' @@ -443,7 +423,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listCollections] errorLabels: [RetryableError, SystemOverloadedError] @@ -467,10 +447,6 @@ tests: commandName: listCollections - commandStartedEvent: commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - commandSucceededEvent: commandName: listCollections - description: 'database.listCollections (read) does not retry if retryReads=false' @@ -512,7 +488,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listCollections] errorLabels: [RetryableError, SystemOverloadedError] @@ -536,10 +512,6 @@ tests: commandName: listCollections - commandStartedEvent: commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - commandSucceededEvent: commandName: listCollections - description: 'database.listCollectionNames (read) does not retry if retryReads=false' @@ -581,7 +553,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [ping] errorLabels: [RetryableError, SystemOverloadedError] @@ -606,10 +578,6 @@ tests: commandName: ping - commandStartedEvent: commandName: ping - - commandFailedEvent: - commandName: ping - - commandStartedEvent: - commandName: ping - commandSucceededEvent: commandName: ping - description: 'database.runCommand (read) does not retry if retryReads=false' @@ -682,7 +650,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -706,10 +674,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'database.createChangeStream (read) does not retry if retryReads=false' @@ -751,7 +715,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -775,10 +739,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'collection.aggregate (read) does not retry if retryReads=false' @@ -820,7 +780,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -844,10 +804,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'collection.countDocuments (read) does not retry if retryReads=false' @@ -889,7 +845,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [count] errorLabels: [RetryableError, SystemOverloadedError] @@ -911,10 +867,6 @@ tests: commandName: count - commandStartedEvent: commandName: count - - commandFailedEvent: - commandName: count - - commandStartedEvent: - commandName: count - commandSucceededEvent: commandName: count - description: 'collection.estimatedDocumentCount (read) does not retry if retryReads=false' @@ -954,7 +906,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [distinct] errorLabels: [RetryableError, SystemOverloadedError] @@ -979,10 +931,6 @@ tests: commandName: distinct - commandStartedEvent: commandName: distinct - - commandFailedEvent: - commandName: distinct - - commandStartedEvent: - commandName: distinct - commandSucceededEvent: commandName: distinct - description: 'collection.distinct (read) does not retry if retryReads=false' @@ -1025,7 +973,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [find] errorLabels: [RetryableError, SystemOverloadedError] @@ -1049,10 +997,6 @@ tests: commandName: find - commandStartedEvent: commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - commandSucceededEvent: commandName: find - description: 'collection.find (read) does not retry if retryReads=false' @@ -1094,7 +1038,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [find] errorLabels: [RetryableError, SystemOverloadedError] @@ -1118,10 +1062,6 @@ tests: commandName: find - commandStartedEvent: commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - commandSucceededEvent: commandName: find - description: 'collection.findOne (read) does not retry if retryReads=false' @@ -1163,7 +1103,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listIndexes] errorLabels: [RetryableError, SystemOverloadedError] @@ -1185,10 +1125,6 @@ tests: commandName: listIndexes - commandStartedEvent: commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - commandSucceededEvent: commandName: listIndexes - description: 'collection.listIndexes (read) does not retry if retryReads=false' @@ -1228,7 +1164,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [listIndexes] errorLabels: [RetryableError, SystemOverloadedError] @@ -1250,10 +1186,6 @@ tests: commandName: listIndexes - commandStartedEvent: commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - commandSucceededEvent: commandName: listIndexes - description: 'collection.listIndexNames (read) does not retry if retryReads=false' @@ -1293,7 +1225,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -1317,10 +1249,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'collection.createChangeStream (read) does not retry if retryReads=false' @@ -1362,7 +1290,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [insert] errorLabels: [RetryableError, SystemOverloadedError] @@ -1386,10 +1314,6 @@ tests: commandName: insert - commandStartedEvent: commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - commandSucceededEvent: commandName: insert - description: 'collection.insertOne (write) does not retry if retryWrites=false' @@ -1431,7 +1355,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [insert] errorLabels: [RetryableError, SystemOverloadedError] @@ -1456,10 +1380,6 @@ tests: commandName: insert - commandStartedEvent: commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - commandSucceededEvent: commandName: insert - description: 'collection.insertMany (write) does not retry if retryWrites=false' @@ -1502,7 +1422,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [delete] errorLabels: [RetryableError, SystemOverloadedError] @@ -1526,10 +1446,6 @@ tests: commandName: delete - commandStartedEvent: commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - commandSucceededEvent: commandName: delete - description: 'collection.deleteOne (write) does not retry if retryWrites=false' @@ -1571,7 +1487,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [delete] errorLabels: [RetryableError, SystemOverloadedError] @@ -1595,10 +1511,6 @@ tests: commandName: delete - commandStartedEvent: commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - commandSucceededEvent: commandName: delete - description: 'collection.deleteMany (write) does not retry if retryWrites=false' @@ -1640,7 +1552,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [update] errorLabels: [RetryableError, SystemOverloadedError] @@ -1665,10 +1577,6 @@ tests: commandName: update - commandStartedEvent: commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - commandSucceededEvent: commandName: update - description: 'collection.replaceOne (write) does not retry if retryWrites=false' @@ -1711,7 +1619,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [update] errorLabels: [RetryableError, SystemOverloadedError] @@ -1736,10 +1644,6 @@ tests: commandName: update - commandStartedEvent: commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - commandSucceededEvent: commandName: update - description: 'collection.updateOne (write) does not retry if retryWrites=false' @@ -1782,7 +1686,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [update] errorLabels: [RetryableError, SystemOverloadedError] @@ -1807,10 +1711,6 @@ tests: commandName: update - commandStartedEvent: commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - commandSucceededEvent: commandName: update - description: 'collection.updateMany (write) does not retry if retryWrites=false' @@ -1853,7 +1753,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [findAndModify] errorLabels: [RetryableError, SystemOverloadedError] @@ -1877,10 +1777,6 @@ tests: commandName: findAndModify - commandStartedEvent: commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - commandSucceededEvent: commandName: findAndModify - description: 'collection.findOneAndDelete (write) does not retry if retryWrites=false' @@ -1922,7 +1818,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [findAndModify] errorLabels: [RetryableError, SystemOverloadedError] @@ -1947,10 +1843,6 @@ tests: commandName: findAndModify - commandStartedEvent: commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - commandSucceededEvent: commandName: findAndModify - description: 'collection.findOneAndReplace (write) does not retry if retryWrites=false' @@ -1993,7 +1885,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [findAndModify] errorLabels: [RetryableError, SystemOverloadedError] @@ -2018,10 +1910,6 @@ tests: commandName: findAndModify - commandStartedEvent: commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - commandSucceededEvent: commandName: findAndModify - description: 'collection.findOneAndUpdate (write) does not retry if retryWrites=false' @@ -2064,7 +1952,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [insert] errorLabels: [RetryableError, SystemOverloadedError] @@ -2090,10 +1978,6 @@ tests: commandName: insert - commandStartedEvent: commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - commandSucceededEvent: commandName: insert - description: 'collection.bulkWrite (write) does not retry if retryWrites=false' @@ -2137,7 +2021,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [createIndexes] errorLabels: [RetryableError, SystemOverloadedError] @@ -2162,10 +2046,6 @@ tests: commandName: createIndexes - commandStartedEvent: commandName: createIndexes - - commandFailedEvent: - commandName: createIndexes - - commandStartedEvent: - commandName: createIndexes - commandSucceededEvent: commandName: createIndexes - description: 'collection.createIndex (write) does not retry if retryWrites=false' @@ -2213,7 +2093,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [dropIndexes] errorLabels: [RetryableError, SystemOverloadedError] @@ -2237,10 +2117,6 @@ tests: commandName: dropIndexes - commandStartedEvent: commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - commandSucceededEvent: commandName: dropIndexes - description: 'collection.dropIndex (write) does not retry if retryWrites=false' @@ -2287,7 +2163,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [dropIndexes] errorLabels: [RetryableError, SystemOverloadedError] @@ -2309,10 +2185,6 @@ tests: commandName: dropIndexes - commandStartedEvent: commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - commandSucceededEvent: commandName: dropIndexes - description: 'collection.dropIndexes (write) does not retry if retryWrites=false' @@ -2352,7 +2224,7 @@ tests: client: *internal_client failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [aggregate] errorLabels: [RetryableError, SystemOverloadedError] @@ -2376,10 +2248,6 @@ tests: commandName: aggregate - commandStartedEvent: commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - commandSucceededEvent: commandName: aggregate - description: 'collection.aggregate (write) does not retry if retryWrites=false' diff --git a/spec/spec_tests/data/client_backpressure/backpressure-retry-max-attempts.yml b/spec/spec_tests/data/client_backpressure/backpressure-retry-max-attempts.yml index 36be3fb8f5..eec89671fa 100644 --- a/spec/spec_tests/data/client_backpressure/backpressure-retry-max-attempts.yml +++ b/spec/spec_tests/data/client_backpressure/backpressure-retry-max-attempts.yml @@ -1,6 +1,6 @@ # Tests in this file are generated from backpressure-retry-max-attempts.yml.template. -description: tests that operations retry at most maxAttempts=5 times +description: tests that operations retry at most maxAttempts=2 times schemaVersion: '1.3' @@ -41,7 +41,7 @@ initialData: - { _id: 2, x: 22 } tests: - - description: 'client.listDatabases retries at most maxAttempts=5 times' + - description: 'client.listDatabases retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -66,20 +66,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listDatabases - commandFailedEvent: @@ -93,7 +81,7 @@ tests: - commandFailedEvent: commandName: listDatabases - - description: 'client.listDatabaseNames retries at most maxAttempts=5 times' + - description: 'client.listDatabaseNames retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -116,20 +104,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases - - commandStartedEvent: - commandName: listDatabases - - commandFailedEvent: - commandName: listDatabases + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listDatabases - commandFailedEvent: @@ -143,7 +119,7 @@ tests: - commandFailedEvent: commandName: listDatabases - - description: 'client.createChangeStream retries at most maxAttempts=5 times' + - description: 'client.createChangeStream retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -168,20 +144,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -195,7 +159,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'client.clientBulkWrite retries at most maxAttempts=5 times' + - description: 'client.clientBulkWrite retries at most maxAttempts=2 times' runOnRequirements: - minServerVersion: '8.0' # client bulk write added to server in 8.0 operations: @@ -225,20 +189,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: bulkWrite - - commandFailedEvent: - commandName: bulkWrite - - commandStartedEvent: - commandName: bulkWrite - - commandFailedEvent: - commandName: bulkWrite - - commandStartedEvent: - commandName: bulkWrite - - commandFailedEvent: - commandName: bulkWrite + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: bulkWrite - commandFailedEvent: @@ -252,7 +204,7 @@ tests: - commandFailedEvent: commandName: bulkWrite - - description: 'database.aggregate read retries at most maxAttempts=5 times' + - description: 'database.aggregate read retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -277,20 +229,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -304,7 +244,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'database.listCollections retries at most maxAttempts=5 times' + - description: 'database.listCollections retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -329,20 +269,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listCollections - commandFailedEvent: @@ -356,7 +284,7 @@ tests: - commandFailedEvent: commandName: listCollections - - description: 'database.listCollectionNames retries at most maxAttempts=5 times' + - description: 'database.listCollectionNames retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -381,20 +309,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections - - commandStartedEvent: - commandName: listCollections - - commandFailedEvent: - commandName: listCollections + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listCollections - commandFailedEvent: @@ -408,7 +324,7 @@ tests: - commandFailedEvent: commandName: listCollections - - description: 'database.runCommand retries at most maxAttempts=5 times' + - description: 'database.runCommand retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -434,20 +350,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: ping - - commandFailedEvent: - commandName: ping - - commandStartedEvent: - commandName: ping - - commandFailedEvent: - commandName: ping - - commandStartedEvent: - commandName: ping - - commandFailedEvent: - commandName: ping + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: ping - commandFailedEvent: @@ -461,7 +365,7 @@ tests: - commandFailedEvent: commandName: ping - - description: 'database.createChangeStream retries at most maxAttempts=5 times' + - description: 'database.createChangeStream retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -486,20 +390,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -513,7 +405,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'collection.aggregate read retries at most maxAttempts=5 times' + - description: 'collection.aggregate read retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -538,20 +430,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -565,7 +445,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'collection.countDocuments retries at most maxAttempts=5 times' + - description: 'collection.countDocuments retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -590,20 +470,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -617,7 +485,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'collection.estimatedDocumentCount retries at most maxAttempts=5 times' + - description: 'collection.estimatedDocumentCount retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -640,20 +508,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: count - - commandFailedEvent: - commandName: count - - commandStartedEvent: - commandName: count - - commandFailedEvent: - commandName: count - - commandStartedEvent: - commandName: count - - commandFailedEvent: - commandName: count + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: count - commandFailedEvent: @@ -667,7 +523,7 @@ tests: - commandFailedEvent: commandName: count - - description: 'collection.distinct retries at most maxAttempts=5 times' + - description: 'collection.distinct retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -693,20 +549,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: distinct - - commandFailedEvent: - commandName: distinct - - commandStartedEvent: - commandName: distinct - - commandFailedEvent: - commandName: distinct - - commandStartedEvent: - commandName: distinct - - commandFailedEvent: - commandName: distinct + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: distinct - commandFailedEvent: @@ -720,7 +564,7 @@ tests: - commandFailedEvent: commandName: distinct - - description: 'collection.find retries at most maxAttempts=5 times' + - description: 'collection.find retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -745,20 +589,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: find - commandFailedEvent: @@ -772,7 +604,7 @@ tests: - commandFailedEvent: commandName: find - - description: 'collection.findOne retries at most maxAttempts=5 times' + - description: 'collection.findOne retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -797,20 +629,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find - - commandStartedEvent: - commandName: find - - commandFailedEvent: - commandName: find + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: find - commandFailedEvent: @@ -824,7 +644,7 @@ tests: - commandFailedEvent: commandName: find - - description: 'collection.listIndexes retries at most maxAttempts=5 times' + - description: 'collection.listIndexes retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -847,20 +667,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listIndexes - commandFailedEvent: @@ -874,7 +682,7 @@ tests: - commandFailedEvent: commandName: listIndexes - - description: 'collection.listIndexNames retries at most maxAttempts=5 times' + - description: 'collection.listIndexNames retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -897,20 +705,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes - - commandStartedEvent: - commandName: listIndexes - - commandFailedEvent: - commandName: listIndexes + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: listIndexes - commandFailedEvent: @@ -924,7 +720,7 @@ tests: - commandFailedEvent: commandName: listIndexes - - description: 'collection.createChangeStream retries at most maxAttempts=5 times' + - description: 'collection.createChangeStream retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -949,20 +745,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: @@ -976,7 +760,7 @@ tests: - commandFailedEvent: commandName: aggregate - - description: 'collection.insertOne retries at most maxAttempts=5 times' + - description: 'collection.insertOne retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1001,20 +785,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: insert - commandFailedEvent: @@ -1028,7 +800,7 @@ tests: - commandFailedEvent: commandName: insert - - description: 'collection.insertMany retries at most maxAttempts=5 times' + - description: 'collection.insertMany retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1054,20 +826,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: insert - commandFailedEvent: @@ -1081,7 +841,7 @@ tests: - commandFailedEvent: commandName: insert - - description: 'collection.deleteOne retries at most maxAttempts=5 times' + - description: 'collection.deleteOne retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1106,20 +866,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: delete - commandFailedEvent: @@ -1133,7 +881,7 @@ tests: - commandFailedEvent: commandName: delete - - description: 'collection.deleteMany retries at most maxAttempts=5 times' + - description: 'collection.deleteMany retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1158,20 +906,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete - - commandStartedEvent: - commandName: delete - - commandFailedEvent: - commandName: delete + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: delete - commandFailedEvent: @@ -1185,7 +921,7 @@ tests: - commandFailedEvent: commandName: delete - - description: 'collection.replaceOne retries at most maxAttempts=5 times' + - description: 'collection.replaceOne retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1211,20 +947,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: update - commandFailedEvent: @@ -1238,7 +962,7 @@ tests: - commandFailedEvent: commandName: update - - description: 'collection.updateOne retries at most maxAttempts=5 times' + - description: 'collection.updateOne retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1264,20 +988,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: update - commandFailedEvent: @@ -1291,7 +1003,7 @@ tests: - commandFailedEvent: commandName: update - - description: 'collection.updateMany retries at most maxAttempts=5 times' + - description: 'collection.updateMany retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1317,20 +1029,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update - - commandStartedEvent: - commandName: update - - commandFailedEvent: - commandName: update + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: update - commandFailedEvent: @@ -1344,7 +1044,7 @@ tests: - commandFailedEvent: commandName: update - - description: 'collection.findOneAndDelete retries at most maxAttempts=5 times' + - description: 'collection.findOneAndDelete retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1369,20 +1069,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: findAndModify - commandFailedEvent: @@ -1396,7 +1084,7 @@ tests: - commandFailedEvent: commandName: findAndModify - - description: 'collection.findOneAndReplace retries at most maxAttempts=5 times' + - description: 'collection.findOneAndReplace retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1422,20 +1110,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: findAndModify - commandFailedEvent: @@ -1449,7 +1125,7 @@ tests: - commandFailedEvent: commandName: findAndModify - - description: 'collection.findOneAndUpdate retries at most maxAttempts=5 times' + - description: 'collection.findOneAndUpdate retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1475,20 +1151,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify - - commandStartedEvent: - commandName: findAndModify - - commandFailedEvent: - commandName: findAndModify + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: findAndModify - commandFailedEvent: @@ -1502,7 +1166,7 @@ tests: - commandFailedEvent: commandName: findAndModify - - description: 'collection.bulkWrite retries at most maxAttempts=5 times' + - description: 'collection.bulkWrite retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1529,20 +1193,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandFailedEvent: - commandName: insert + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: insert - commandFailedEvent: @@ -1556,7 +1208,7 @@ tests: - commandFailedEvent: commandName: insert - - description: 'collection.createIndex retries at most maxAttempts=5 times' + - description: 'collection.createIndex retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1582,20 +1234,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: createIndexes - - commandFailedEvent: - commandName: createIndexes - - commandStartedEvent: - commandName: createIndexes - - commandFailedEvent: - commandName: createIndexes - - commandStartedEvent: - commandName: createIndexes - - commandFailedEvent: - commandName: createIndexes + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: createIndexes - commandFailedEvent: @@ -1609,7 +1249,7 @@ tests: - commandFailedEvent: commandName: createIndexes - - description: 'collection.dropIndex retries at most maxAttempts=5 times' + - description: 'collection.dropIndex retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1634,20 +1274,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: dropIndexes - commandFailedEvent: @@ -1661,7 +1289,7 @@ tests: - commandFailedEvent: commandName: dropIndexes - - description: 'collection.dropIndexes retries at most maxAttempts=5 times' + - description: 'collection.dropIndexes retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1684,20 +1312,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes - - commandStartedEvent: - commandName: dropIndexes - - commandFailedEvent: - commandName: dropIndexes + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: dropIndexes - commandFailedEvent: @@ -1711,7 +1327,7 @@ tests: - commandFailedEvent: commandName: dropIndexes - - description: 'collection.aggregate write retries at most maxAttempts=5 times' + - description: 'collection.aggregate write retries at most maxAttempts=2 times' operations: - name: failPoint object: testRunner @@ -1736,20 +1352,8 @@ tests: expectEvents: - client: *client events: - # we expect 6 pairs of command started and succeeded events: - # 1 initial attempt and 5 retries. - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate - - commandStartedEvent: - commandName: aggregate - - commandFailedEvent: - commandName: aggregate + # we expect 3 pairs of command started and succeeded events: + # 1 initial attempt and 2 retries. - commandStartedEvent: commandName: aggregate - commandFailedEvent: diff --git a/spec/spec_tests/data/client_backpressure/getMore-retried.yml b/spec/spec_tests/data/client_backpressure/getMore-retried.yml index d7111f6e50..cd8198383a 100644 --- a/spec/spec_tests/data/client_backpressure/getMore-retried.yml +++ b/spec/spec_tests/data/client_backpressure/getMore-retried.yml @@ -38,7 +38,7 @@ tests: client: *failPointClient failPoint: configureFailPoint: failCommand - mode: { times: 3 } + mode: { times: 2 } data: failCommands: [getMore] errorLabels: [RetryableError, SystemOverloadedError] @@ -70,11 +70,6 @@ tests: - commandFailedEvent: commandName: getMore # second attempt - - commandStartedEvent: - commandName: getMore - - commandFailedEvent: - commandName: getMore - # third attempt - commandStartedEvent: commandName: getMore - commandFailedEvent: @@ -85,7 +80,7 @@ tests: - commandSucceededEvent: commandName: getMore - - description: "getMores are retried maxAttempts=5 times" + - description: "getMores are retried maxAttempts=2 times" operations: - name: failPoint object: testRunner @@ -126,21 +121,6 @@ tests: - commandFailedEvent: commandName: getMore # third attempt - - commandStartedEvent: - commandName: getMore - - commandFailedEvent: - commandName: getMore - # fourth attempt - - commandStartedEvent: - commandName: getMore - - commandFailedEvent: - commandName: getMore - # fifth attempt - - commandStartedEvent: - commandName: getMore - - commandFailedEvent: - commandName: getMore - # final attempt - commandStartedEvent: commandName: getMore - commandFailedEvent: diff --git a/spec/spec_tests/data/transactions_unified/backpressure-retryable-abort.yml b/spec/spec_tests/data/transactions_unified/backpressure-retryable-abort.yml index 85532e1f60..bd8180dd1f 100644 --- a/spec/spec_tests/data/transactions_unified/backpressure-retryable-abort.yml +++ b/spec/spec_tests/data/transactions_unified/backpressure-retryable-abort.yml @@ -132,7 +132,7 @@ tests: - collectionName: *collection_name databaseName: *database_name documents: [] - - description: abortTransaction is retried maxAttempts=5 times if backpressure labels are added + - description: abortTransaction is retried maxAttempts=2 times if backpressure labels are added operations: - object: testRunner name: failPoint @@ -201,12 +201,6 @@ tests: commandName: abortTransaction - commandStartedEvent: commandName: abortTransaction - - commandStartedEvent: - commandName: abortTransaction - - commandStartedEvent: - commandName: abortTransaction - - commandStartedEvent: - commandName: abortTransaction outcome: - collectionName: *collection_name databaseName: *database_name diff --git a/spec/spec_tests/data/transactions_unified/backpressure-retryable-commit.yml b/spec/spec_tests/data/transactions_unified/backpressure-retryable-commit.yml index 8099e1c1eb..8ee1b96c7f 100644 --- a/spec/spec_tests/data/transactions_unified/backpressure-retryable-commit.yml +++ b/spec/spec_tests/data/transactions_unified/backpressure-retryable-commit.yml @@ -135,7 +135,7 @@ tests: databaseName: *database_name documents: - _id: 1 - - description: commitTransaction is retried maxAttempts=5 times if backpressure labels are added + - description: commitTransaction is retried maxAttempts=2 times if backpressure labels are added runOnRequirements: - serverless: forbid operations: @@ -208,12 +208,6 @@ tests: commandName: commitTransaction - commandStartedEvent: commandName: commitTransaction - - commandStartedEvent: - commandName: commitTransaction - - commandStartedEvent: - commandName: commitTransaction - - commandStartedEvent: - commandName: commitTransaction outcome: - collectionName: *collection_name databaseName: *database_name diff --git a/spec/spec_tests/data/transactions_unified/backpressure-retryable-reads.yml b/spec/spec_tests/data/transactions_unified/backpressure-retryable-reads.yml index 18bbdaadbf..7edc41fa47 100644 --- a/spec/spec_tests/data/transactions_unified/backpressure-retryable-reads.yml +++ b/spec/spec_tests/data/transactions_unified/backpressure-retryable-reads.yml @@ -134,7 +134,7 @@ tests: $$exists: false commandName: commitTransaction databaseName: admin - - description: reads are retried maxAttempts=5 times if backpressure labels are added + - description: reads are retried maxAttempts=2 times if backpressure labels are added operations: - object: *session0 name: startTransaction @@ -182,11 +182,5 @@ tests: commandName: find - commandStartedEvent: commandName: find - - commandStartedEvent: - commandName: find - - commandStartedEvent: - commandName: find - - commandStartedEvent: - commandName: find - commandStartedEvent: commandName: abortTransaction diff --git a/spec/spec_tests/data/transactions_unified/backpressure-retryable-writes.yml b/spec/spec_tests/data/transactions_unified/backpressure-retryable-writes.yml index ced8373e35..68c86cff2b 100644 --- a/spec/spec_tests/data/transactions_unified/backpressure-retryable-writes.yml +++ b/spec/spec_tests/data/transactions_unified/backpressure-retryable-writes.yml @@ -147,7 +147,7 @@ tests: documents: - { _id: 1 } - { _id: 2 } - - description: writes are retried maxAttempts=5 times if backpressure labels are added + - description: writes are retried maxAttempts=2 times if backpressure labels are added operations: - object: *session0 name: startTransaction @@ -196,12 +196,6 @@ tests: commandName: insert - commandStartedEvent: commandName: insert - - commandStartedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - - commandStartedEvent: - commandName: insert - commandStartedEvent: commandName: abortTransaction outcome: diff --git a/spec/spec_tests/data/uri_options/client-backpressure-options.yml b/spec/spec_tests/data/uri_options/client-backpressure-options.yml new file mode 100644 index 0000000000..c750b32e23 --- /dev/null +++ b/spec/spec_tests/data/uri_options/client-backpressure-options.yml @@ -0,0 +1,53 @@ +tests: + - + description: "maxAdaptiveRetries is parsed correctly" + uri: "mongodb://example.com/?maxAdaptiveRetries=3" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + maxAdaptiveRetries: 3 + - + description: "maxAdaptiveRetries=0 is parsed correctly" + uri: "mongodb://example.com/?maxAdaptiveRetries=0" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + maxAdaptiveRetries: 0 + - + description: "maxAdaptiveRetries with invalid value causes a warning" + uri: "mongodb://example.com/?maxAdaptiveRetries=-5" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ + - + description: "enableOverloadRetargeting is parsed correctly" + uri: "mongodb://example.com/?enableOverloadRetargeting=true" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + enableOverloadRetargeting: true + - + description: "enableOverloadRetargeting=false is parsed correctly" + uri: "mongodb://example.com/?enableOverloadRetargeting=false" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + enableOverloadRetargeting: false + - + description: "enableOverloadRetargeting with invalid value causes a warning" + uri: "mongodb://example.com/?enableOverloadRetargeting=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~