Skip to content

Instantly share code, notes, and snippets.

@jakimowicz
Forked from bhbryant/retry.rb
Last active December 26, 2015 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakimowicz/7217846 to your computer and use it in GitHub Desktop.
Save jakimowicz/7217846 to your computer and use it in GitHub Desktop.
auto-failover ReplicaSet config for MongoMapper, by way of ruby driver. without any change to the connection. You just need to require the files before initiating the connection.
require 'lib/mongo/retry'
require 'lib/mongo/repl_set_connection'
class Mongo::ReplSetConnection
## wraps basic send message calls in catch blocks to auto retry connection
## per: http://permalink.gmane.org/gmane.comp.db.mongodb.user/25261
# After looking at the Ruby MongoDB driver code it appears that we could
# handle this transparently in the following methods:
# Connection::send_message
# Connection::send_message_with_safe_check
# Connection::receive_message
# I put together a new Connection class that is derived from
# ReplSetConnection to implement this behavior.
## This is ripped from Mongoid block
include Mongo::Retry
alias_method :send_message_original, :send_message
def send_message(*args)
retry_on_connection_failure do
send_message_original *args
end
end
alias_method :send_message_with_safe_check_original, :send_message_with_safe_check
def send_message_with_safe_check(*args)
retry_on_connection_failure do
send_message_with_safe_check_original *args
end
end
alias_method :receive_message_original, :receive_message
def receive_message(*args)
retry_on_connection_failure do
receive_message_original *args
end
end
end
# encoding: utf-8
## pulled from mongoid
# Provides behaviour for retrying commands on connection failure.
module Mongo::Retry
# Retries command on connection failures.
#
# This is useful when using replica sets. When a primary server wents
# down and a command is issued, the driver will raise a
# Mongo::ConnectionFailure. We wait a little bit, because nodes are
# electing themselves, and then retry the given command.
#
# By setting Mongoid.max_retries_on_connection_failure to a value of 0,
# no attempt will be made, immediately raising connection failure.
# Otherwise it will attempt to make the specified number of retries
# and then raising the exception to clients.
#
# @example Retry the command.
# retry_on_connection_failure do
# collection.send(name, *args)
# end
#
# @since 2.0.0
def retry_on_connection_failure
retries = 0
begin
yield
rescue Mongo::ConnectionFailure => ex
retries = increase_retry_attempts(retries, ex)
retry
rescue Mongo::OperationFailure => ex
if ex.message =~ /not master/
retries = increase_retry_attempts(retries, ex)
retry
else
raise ex
end
end
end
private
def increase_retry_attempts(retries, ex)
retries += 1
raise ex if retries > 30 # Config.max_retries_on_connection_failure
Kernel.sleep(0.5) ## Todo.. modify for event machine
log_retry retries
retries
end
def log_retry(retry_number)
Rails.logger.warn "A Mongo::ConnectionFailure was raised. Retry attempt ##{retry_number}."
rescue
puts "A Mongo::ConnectionFailure was raised. Retry attempt ##{retry_number}."
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment