lib/mongo/retryable.rb in mongo-2.5.0.beta vs lib/mongo/retryable.rb in mongo-2.5.0
- old
+ new
@@ -28,11 +28,10 @@
# ...
# end
#
# @note This only retries read operations on socket errors.
#
- # @param [ Integer ] attempt The retry attempt count - for internal use.
# @param [ Proc ] block The block to execute.
#
# @yieldparam [ Server ] server The server to which the write should be sent.
#
# @return [ Result ] The result of the operation.
@@ -97,27 +96,71 @@
# @param [ Proc ] block The block to execute.
#
# @return [ Result ] The result of the operation.
#
# @since 2.1.0
- def write_with_retry(session, server_selector)
+ def write_with_retry(session, write_concern, &block)
+ unless retry_write_allowed?(session, write_concern)
+ return legacy_write_with_retry(&block)
+ end
+
+ server = cluster.next_primary
+ unless server.retry_writes?
+ return legacy_write_with_retry(server, &block)
+ end
+
+ begin
+ txn_num = session.next_txn_num
+ yield(server, txn_num)
+ rescue Error::SocketError, Error::SocketTimeoutError => e
+ retry_write(e, txn_num, &block)
+ rescue Error::OperationFailure => e
+ raise e unless e.write_retryable?
+ retry_write(e, txn_num, &block)
+ end
+ end
+
+ private
+
+ def retry_write_allowed?(session, write_concern)
+ session && session.retry_writes? &&
+ (write_concern.nil? || write_concern.acknowledged?)
+ end
+
+ def retry_write(original_error, txn_num, &block)
+ cluster.scan!
+ server = cluster.next_primary
+ raise original_error unless (server.retry_writes? && txn_num)
+ log_retry(original_error)
+ yield(server, txn_num)
+ rescue Error::SocketError, Error::SocketTimeoutError => e
+ cluster.scan!
+ raise e
+ rescue Error::OperationFailure => e
+ raise original_error unless e.write_retryable?
+ cluster.scan!
+ raise e
+ rescue
+ raise original_error
+ end
+
+ def legacy_write_with_retry(server = nil)
attempt = 0
begin
attempt += 1
- yield(server_selector.call)
+ yield(server || cluster.next_primary)
rescue Error::OperationFailure => e
+ server = nil
raise(e) if attempt > Cluster::MAX_WRITE_RETRIES
if e.write_retryable?
log_retry(e)
cluster.scan!
retry
else
raise(e)
end
end
end
-
- private
# Log a warning so that any application slow down is immediately obvious.
def log_retry(e)
Logger.logger.warn "Retry due to: #{e.class.name} #{e.message}"
end