Skip to content

Instantly share code, notes, and snippets.

@mrkurt
Forked from bhbryant/retry.rb
Created March 30, 2012 20:26
Show Gist options
  • Save mrkurt/2254747 to your computer and use it in GitHub Desktop.
Save mrkurt/2254747 to your computer and use it in GitHub Desktop.
auto-failover ReplicaSet config for MongoMapper, by way of ruby driver
replica_sets = mm_env['replica_sets'] # node1:port&node2:port
rs_list = replica_sets.split("&").map {|rs| host,port = rs.split(":"); [host,port.to_i] }
MongoMapper.connection = Mongo::RetryReplicaSetConnection.new(*(rs_list << {:read_secondary => true, :auto_refresh => true }))
MongoMapper.database = mm_env['database']
MongoMapper.database.authenticate(mm_env['username'], mm_env['password'])
# 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 += 1
raise ex if retries > 30 # Config.max_retries_on_connection_failure
Kernel.sleep(0.5) ## Todo.. modify for event machine
log_retry retries
retry
rescue Mongo::OperationFailure => ex
if ex.message =~ /not master/
retries += 1
raise ex if retries > 30
Kernel.sleep(0.5)
log_retry retries
retry
else
raise ex
end
end
end
private
def log_retry(retry_number)
puts "A Mongo::ConnectionFailure was raised. Retry attempt ##{retry_number}."
end
end
class Mongo::RetryReplicaSetConnection < 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
def send_message(operation, message, opts={})
retry_on_connection_failure do
super(operation, message, opts)
end
end
def send_message_with_safe_check(operation, message, db_name, log_message=nil, last_error_params=false)
retry_on_connection_failure do
super(operation, message, db_name, log_message, last_error_params)
end
end
def receive_message(operation, message, log_message=nil, socket=nil, command=false)
retry_on_connection_failure do
super(operation, message, log_message, socket, command)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment