module JamRuby # The purpose of this class is to handle reconnect logic and 'recover' logic (which means automatically resubscribe to topics/queues). # It's 'leaky' in that it will give you a AMQP::Channel to do these subscriptions yourself in the block you pass to connect. # Use the *connected* property to check if the connection is currently up. class AmqpConnectionManager attr_accessor :should_reconnect, :reconnect_interval, :connection, :connect, :connect_options, :connect_block, :channel, :connected def initialize(should_reconnect, reconnect_interval, connect_options = {}) @should_reconnect = should_reconnect @reconnect_interval = reconnect_interval @connect_options = connect_options @connected = false @log = Logging.logger[self] end # the block you pass in will be passed a channel upon successful connect. You need # def connect(&block) @connect = true # indicate that we should be connected @connect_block = block try_connect end def try_connect @connection = AMQP.connect(@connect_options, &method(:successful_connect)) @connection.on_tcp_connection_failure(&method(:on_tcp_connection_failure)) @connection.on_tcp_connection_loss(&method(:on_tcp_connection_loss)) @connection.on_recovery(&method(:on_recovery)) @connection.on_error(&method(:on_error)) end def successful_connect(connection) @log.debug "connected to #{@connect_options}" @connected = true @channel = AMQP::Channel.new(connection) @channel.auto_recovery = true unless @connect_block.nil? @connect_block.call(@channel) end end def on_tcp_connection_failure(settings) @connected = false if @connect && @should_reconnect @log.warn "[network failure] Trying to connect in 4 seconds to #{@connect_options}" EventMachine.add_timer(@reconnect_interval, &method(:try_connect)) end end def on_tcp_connection_loss(conn, settings) @connected = false if @connect && @should_reconnect @log.warn "[network failure] Trying to reconnect..." conn.reconnect(false, @reconnect_interval) end end def on_recovery(conn, settings) @connected = true @log.debug "reconnected #{conn} #{settings}" #puts "#channel before #{@channel}" #puts "recovered channel: #{@channel.reuse}" end def disconnect @connect = false # indicate that we should no longer be connected unless @connection.nil? if @connection.connected? @connection.disconnect do @connected = false @log.debug "disconnected" end end end end def on_error(connection, connection_close) @log.error "Handling a connection-level exception." @log.error "AMQP class id : #{connection_close.class_id}" @log.error "AMQP method id: #{connection_close.method_id}" @log.error "Status code : #{connection_close.reply_code}" @log.error "Error message : #{connection_close.reply_text}" end def connected? return @connected end end end