lib/mongo/retryable.rb in mongo-2.12.4 vs lib/mongo/retryable.rb in mongo-2.13.0.beta1

- old
+ new

@@ -1,6 +1,6 @@ -# Copyright (C) 2015-2019 MongoDB, Inc. +# Copyright (C) 2015-2020 MongoDB Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # @@ -219,20 +219,20 @@ begin yield(server, txn_num, false) rescue Error::SocketError, Error::SocketTimeoutError => e e.add_note('modern retry') e.add_note("attempt 1") - if session.in_transaction? && !ending_transaction + if !e.label?('RetryableWriteError') raise e end retry_write(e, session, txn_num, &block) rescue Error::OperationFailure => e e.add_note('modern retry') e.add_note("attempt 1") if e.unsupported_retryable_write? raise_unsupported_error(e) - elsif (session.in_transaction? && !ending_transaction) || !e.write_retryable? + elsif !e.label?('RetryableWriteError') raise e end retry_write(e, session, txn_num, &block) end @@ -296,11 +296,11 @@ e.add_note("attempt #{attempt}") server = nil if attempt > client.max_write_retries raise e end - if e.write_retryable? && !(session && session.in_transaction?) + if e.label?('RetryableWriteError') log_retry(e, message: 'Legacy write retry') cluster.scan!(false) retry else raise e @@ -379,13 +379,15 @@ end def retry_read(original_error, server_selector, session, &block) begin server = select_server(cluster, server_selector, session) - rescue => e + rescue Error, Error::AuthError => e original_error.add_note("later retry failed: #{e.class}: #{e}") - raise original_error + + # See the corresponding note below in retry_write. + raise Error::RaiseOriginalError end log_retry(original_error, message: 'Read retry') begin @@ -400,15 +402,17 @@ original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end e.add_note("attempt 2") raise e - rescue => e + rescue Error, Error::AuthError => e e.add_note('modern retry') original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end + rescue Error::RaiseOriginalError + raise original_error end def retry_write(original_error, session, txn_num, &block) # We do not request a scan of the cluster here, because error handling # for the error which triggered the retry should have updated the @@ -418,30 +422,39 @@ server = select_server(cluster, ServerSelector.primary, session) unless server.retry_writes? # Do not need to add "modern retry" here, it should already be on # the first exception. original_error.add_note('did not retry because server selected for retry does not supoprt retryable writes') - raise original_error + + # When we want to raise the original error, we must not run the + # rescue blocks below that add diagnostics because the diagnostics + # added would either be rendundant (e.g. modern retry note) or wrong + # (e.g. "attempt 2", we are raising the exception produced in the + # first attempt and haven't attempted the second time). Use the + # special marker class to bypass the ordinarily applicable rescues. + raise Error::RaiseOriginalError end log_retry(original_error, message: 'Write retry') yield(server, txn_num, true) rescue Error::SocketError, Error::SocketTimeoutError => e e.add_note('modern retry') e.add_note('attempt 2') raise e rescue Error::OperationFailure => e e.add_note('modern retry') - if e.write_retryable? + if e.label?('RetryableWriteError') e.add_note('attempt 2') raise e else original_error.add_note("later retry failed: #{e.class}: #{e}") raise original_error end - rescue => e + rescue Error, Error::AuthError => e # Do not need to add "modern retry" here, it should already be on # the first exception. original_error.add_note("later retry failed: #{e.class}: #{e}") + raise original_error + rescue Error::RaiseOriginalError raise original_error end # This is a separate method to make it possible for the test suite to # assert that server selection is performed during retry attempts.