コード例 #1
0
ファイル: queue_connection.py プロジェクト: weburnit/cronq
 def _create_connection(self):
     "Tries to create a connection, returns True on success"
     self._connection = None
     self._last_confirmed_message = None
     host = self._get_next_host()
     self._logger.debug('Trying to connect to {}'.format(host))
     try:
         self._connection = RabbitConnection(
             host=host,
             port=self._connection_port,
             user=self._connection_user,
             password=self._connection_password,
             vhost=self._connection_path,
             close_cb=self._close_cb,
             heartbeat=self._connection_heartbeat,
             client_properties={
                 'connection_name': self._connection_name,
             },
         )
     except socket.error as exc:
         self._logger.error('Error connecting to rabbitmq {}'.format(exc))
         return False
     self._channel = self._connection.channel()
     if self._confirm:
         self._channel.confirm.select(nowait=False)
         self._channel.basic.set_ack_listener(self._ack)
     self._logger.debug('Connected to {}'.format(host))
     return True
コード例 #2
0
ファイル: client.py プロジェクト: lipixun/pytest
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()
        result = self._channel.queue.declare(exclusive = True)
        self._callbackQueue = result[0]
        self._channel.basic.consume(self._callbackQueue, self.onResponse, no_ack = True)
        self._response = None

    def onResponse(self, message):
        """On response
        """
        correlationID = message.properties.get('correlation_id')
        print 'Receive server response [%s] correlationID [%s]' % (message.body, correlationID)
        self._response = int(message.body)

    def call(self, number):
        """The call method
        """
        self._response = None
        corrID = str(uuid4())
        print 'Call server with request [%s] correlationID [%s]' % (number, corrID)
        self._channel.basic.publish(Message(str(number), reply_to = self._callbackQueue, correlation_id = corrID), '', 'test_rpc')
        while self._response is None:
            self._conn.read_frames()
        # Done
        return self._response
コード例 #3
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_meta', auto_delete=True)
        self._channel.basic.consume('test_meta', self.callback, no_ack=False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callback(self, message):
        """The callee method
        """
        body = message.body
        deliveryInfo = message.delivery_info
        properties = message.properties
        # Print the meta
        print 'Receive message body [%s] deliveryInfo [%s] properties [%s]' % (
            body, deliveryInfo, properties)
        # ACK
        deliveryTag = deliveryInfo.get('delivery_tag')
        self._channel.basic.ack(deliveryTag)
コード例 #4
0
ファイル: inspector.py プロジェクト: lipixun/pytest
class Inspector(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_event', auto_delete = True)
        self._channel.queue.bind('test_event', exchange = 'amq.rabbitmq.event', routing_key = '#')
        self._channel.basic.consume('test_event', self.callback, no_ack = False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callback(self, message):
        """The callee method
        """
        body = message.body
        eventType = message.delivery_info.get('routing_key')
        deliveryTag = message.delivery_info.get('delivery_tag')
        # Print the meta
        print 'Event [%s] message body [%s] headers [%s] deliveryInfo [%s]' % (eventType, body, message.properties, message.delivery_info)
        # ACK
        self._channel.basic.ack(deliveryTag)
コード例 #5
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The RPC Server
    """

    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host, port=port, vhost=vhost, user=user, password=password)
        self._channel = self._conn.channel()
        self._channel.queue.declare("test_rpc", auto_delete=True)
        self._channel.basic.consume("test_rpc", self.callee, no_ack=False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callee(self, message):
        """The callee method
        """
        num = int(message.body)
        replyTo = message.properties.get("reply_to")
        correlationID = message.properties.get("correlation_id")
        deliveryTag = message.delivery_info.get("delivery_tag")
        # Print the meta
        print "Receive message body [%s] replyTo [%s] correlationID [%s]" % (num, replyTo, correlationID)
        # Return add 1
        self._channel.basic.publish(Message(str(num + 1), correlation_id=correlationID), "", replyTo)
        # ACK
        self._channel.basic.ack(deliveryTag)
コード例 #6
0
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(transport='gevent',
                                      host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        gevent.spawn(self.loop)
        self._channel = self._conn.channel()

    def loop(self):
        """The loop
        """
        while self._conn:
            self._conn.read_frames()
            gevent.sleep()

    def call(self):
        """The call method
        """
        self._channel.basic.publish(Message('A test body'), '', 'test_gevent')
コード例 #7
0
ファイル: inspector.py プロジェクト: lipixun/pytest
class Inspector(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_dead_channel', auto_delete = True)
        self._channel.queue.bind('test_dead_channel', exchange = 'amq.topic', routing_key = 'test.dead_channel')
        self._channel.basic.consume('test_dead_channel', self.callback, no_ack = False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callback(self, message):
        """The callee method
        """
        body = message.body
        deliveryInfo = message.delivery_info
        # Print body
        print 'Receive dead message [%s]' % body
        # ACK
        deliveryTag = deliveryInfo.get('delivery_tag')
        self._channel.basic.ack(deliveryTag)
コード例 #8
0
ファイル: inspector.py プロジェクト: lipixun/pytest
class Inspector(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_event', auto_delete=True)
        self._channel.queue.bind('test_event',
                                 exchange='amq.rabbitmq.event',
                                 routing_key='#')
        self._channel.basic.consume('test_event', self.callback, no_ack=False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callback(self, message):
        """The callee method
        """
        body = message.body
        eventType = message.delivery_info.get('routing_key')
        deliveryTag = message.delivery_info.get('delivery_tag')
        # Print the meta
        print 'Event [%s] message body [%s] headers [%s] deliveryInfo [%s]' % (
            eventType, body, message.properties, message.delivery_info)
        # ACK
        self._channel.basic.ack(deliveryTag)
コード例 #9
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_meta', auto_delete = True)
        self._channel.basic.consume('test_meta', self.callback, no_ack = False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callback(self, message):
        """The callee method
        """
        body = message.body
        deliveryInfo = message.delivery_info
        properties = message.properties
        # Print the meta
        print 'Receive message body [%s] deliveryInfo [%s] properties [%s]' % (body, deliveryInfo, properties)
        # ACK
        deliveryTag = deliveryInfo.get('delivery_tag')
        self._channel.basic.ack(deliveryTag)
コード例 #10
0
ファイル: inspector.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
     self._channel = self._conn.channel()
     self._channel.queue.declare('test_dead_channel', auto_delete = True)
     self._channel.queue.bind('test_dead_channel', exchange = 'amq.topic', routing_key = 'test.dead_channel')
     self._channel.basic.consume('test_dead_channel', self.callback, no_ack = False)
コード例 #11
0
ファイル: going2dead.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
     self._channel = self._conn.channel()
     result = self._channel.queue.declare(arguments = { 'x-dead-letter-exchange': 'amq.topic', 'x-dead-letter-routing-key': 'test.dead_channel' })
     self._deadQueue = result[0]
     # Send a message
     self._channel.basic.publish(Message('OMG! I\'m dead!'), '', self._deadQueue)
コード例 #12
0
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host=host,
                                   port=port,
                                   vhost=vhost,
                                   user=user,
                                   password=password)
     self._channel = self._conn.channel()
コード例 #13
0
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password, open_cb = self.onConnected)
     gevent.spawn(self.loop)
     self._channel = self._conn.channel()
     self._channel.basic.qos(prefetch_count = 10)
     self._channel.queue.declare('test_confirm', auto_delete = True)
     self._channel.basic.consume('test_confirm', self.callback, no_ack = False)
コード例 #14
0
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password)
     gevent.spawn(self.loop)
     self._channel = self._conn.channel()
     self._channel.confirm.select()
     self._channel.basic.set_return_listener(self.onBasicReturn)
     self._channel.basic.set_ack_listener(self.onDeliverAck)
     self._channel.basic.set_nack_listener(self.onDeliverNAck)
コード例 #15
0
ファイル: server.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host=host,
                                   port=port,
                                   vhost=vhost,
                                   user=user,
                                   password=password)
     self._channel = self._conn.channel()
     self._channel.queue.declare('test_meta', auto_delete=True)
     self._channel.basic.consume('test_meta', self.callback, no_ack=False)
コード例 #16
0
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(transport='gevent',
                                   host=host,
                                   port=port,
                                   vhost=vhost,
                                   user=user,
                                   password=password)
     gevent.spawn(self.loop)
     self._channel = self._conn.channel()
コード例 #17
0
ファイル: client.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host=host,
                                   port=port,
                                   vhost=vhost,
                                   user=user,
                                   password=password)
     self._channel = self._conn.channel()
     result = self._channel.queue.declare(exclusive=True)
     self._callbackQueue = result[0]
     self._channel.basic.consume(self._callbackQueue,
                                 self.onResponse,
                                 no_ack=True)
     self._response = None
コード例 #18
0
ファイル: server.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
     self._channel = self._conn.channel()
     self._channel.queue.declare('test_meta', auto_delete = True)
     self._channel.basic.consume('test_meta', self.callback, no_ack = False)
コード例 #19
0
ファイル: queue_connection.py プロジェクト: seatgeek/cronq
 def _create_connection(self):
     "Tries to create a connection, returns True on success"
     self._connection = None
     self._last_confirmed_message = None
     host = self._get_next_host()
     self._logger.debug('Trying to connect to {}'.format(host))
     try:
         self._connection = RabbitConnection(
             host=host,
             port=self._connection_port,
             user=self._connection_user,
             password=self._connection_password,
             vhost=self._connection_path,
             close_cb=self._close_cb,
             heartbeat=self._connection_heartbeat,
             client_properties={
                 'connection_name': self._connection_name,
             },
         )
     except socket.error as exc:
         self._logger.error('Error connecting to rabbitmq {}'.format(exc))
         return False
     self._channel = self._connection.channel()
     if self._confirm:
         self._channel.confirm.select(nowait=False)
         self._channel.basic.set_ack_listener(self._ack)
     self._logger.debug('Connected to {}'.format(host))
     return True
コード例 #20
0
    def __init__(self, connectionParams=None, channelConfigCb=None):
        """
    NOTE: Connection establishment may be performed in the scope of the
    constructor or on demand, depending on the underlying implementation

    :param nta.utils.amqp.connection.ConnectionParams connectionParams:
      parameters for connecting to AMQP broker;
      [default=default params for RabbitMQ broker on localhost]
    :param channelConfigCb: An optional callback function that will be
      called whenever a new AMQP Channel is being brought up
    :type channelConfigCb: None or callable with the signature
      channelConfigCb(SynchronousAmqpClient)
    """
        self._channelConfigCb = channelConfigCb

        # Holds _ChannelContext when channel is created; we create the channel on
        # demand. The implementation accesses this member via the
        # `_liveChannelContext` property getter when it's desirable to bring up the
        # channel on-on demand. When it's undesirable to bring up the channel, the
        # implementation interacts directly with this member, which will be None
        # when we don't have a channel.
        self._channelContextInstance = None

        # Set to True when user calls close, so we know to not raise an exception
        # from our _on*Closed callback methods
        self._userInitiatedClosing = False

        # Instantiate underlying connection object
        params = (connectionParams if connectionParams is not None else
                  amqp_connection.ConnectionParams())

        # NOTE: we could get a `close_cb` call from RabbitConnection constructor, so
        # prepare for it by initializing `self._connection`
        self._connection = None
        self._connection = RabbitConnection(
            transport="socket",
            sock_opts={(socket.IPPROTO_TCP, socket.TCP_NODELAY): 1},
            synchronous=True,
            close_cb=self._onConnectionClosed,
            user=params.credentials.username,
            password=params.credentials.password,
            vhost=params.vhost,
            host=params.host,
            port=params.port,
            heartbeat=self._DEFAULT_HEARTBEAT_TIMEOUT_SEC,
            logger=g_log)
コード例 #21
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(transport='gevent',
                                      host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        gevent.spawn(self.loop)
        self._channel = self._conn.channel()
        self._channel.basic.qos(prefetch_count=10)
        self._channel.queue.declare('test_gevent', auto_delete=True)
        self._channel.basic.consume('test_gevent', self.callback, no_ack=False)

    def loop(self):
        """Waiting for response
        """
        while self._conn:
            self._conn.read_frames()
            gevent.sleep()

    def callback(self, message):
        """The callee method
        """
        # NOTE:
        #   Here, we have to spawn the actually message processing method in order to process the message parallely
        gevent.spawn(self.process, message)

    def process(self, message):
        """Process the message
        """
        body = message.body
        deliveryInfo = message.delivery_info
        deliveryTag = deliveryInfo.get('delivery_tag')
        # Print the meta
        print 'Receive message body [%s] deliveryTag [%s], will sleep 10s' % (
            body, deliveryTag)
        gevent.sleep(10)
        # ACK
        print 'Wake up, ACK the message'
        self._channel.basic.ack(deliveryTag)
コード例 #22
0
ファイル: client.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
     self._channel = self._conn.channel()
     result = self._channel.queue.declare(exclusive = True)
     self._callbackQueue = result[0]
     self._channel.basic.consume(self._callbackQueue, self.onResponse, no_ack = True)
     self._response = None
コード例 #23
0
ファイル: eventsender.py プロジェクト: lipixun/pytest
class EventSender(object):
    """The event sender
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new EventSender
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('_aprefix/%s/webservice/%s' % (socket.gethostname(), os.getpid()), exclusive = True)
コード例 #24
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The Meta Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password, open_cb = self.onConnected)
        gevent.spawn(self.loop)
        self._channel = self._conn.channel()
        self._channel.basic.qos(prefetch_count = 10)
        self._channel.queue.declare('test_confirm', auto_delete = True)
        self._channel.basic.consume('test_confirm', self.callback, no_ack = False)

    def onConnected(self):
        """On connected
        """
        print 'Connected'

    def loop(self):
        """Waiting for response
        """
        while self._conn:
            self._conn.read_frames()
            gevent.sleep()

    def callback(self, message):
        """The callee method
        """
        # NOTE:
        #   Here, we have to spawn the actually message processing method in order to process the message parallely
        gevent.spawn(self.process, message)

    def process(self, message):
        """Process the message
        """
        body = message.body
        deliveryInfo = message.delivery_info
        deliveryTag = deliveryInfo.get('delivery_tag')
        # Print the meta
        print 'Receive message body [%s] deliveryTag [%s], will sleep 10s' % (body, deliveryTag)
        gevent.sleep(10)
        # ACK
        print 'Wake up, ACK the message'
        self._channel.basic.ack(deliveryTag)
コード例 #25
0
ファイル: rabbit_connection.py プロジェクト: r3sult/cronq
def plain_rabbit_connection_to_hosts(hosts, **kwargs):
    for host in hosts:
        logger.info('Trying to connect to host: {0}'.format(host))
        try:
            conn = RabbitConnection(host=host, **kwargs)
            logger.info("...success")
            return conn
        except socket.error:
            logger.info('Error connecting to {0}'.format(host))
    logger.error('Could not connect to any hosts')
コード例 #26
0
ファイル: client.py プロジェクト: lipixun/pytest
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        self._channel = self._conn.channel()
        result = self._channel.queue.declare(exclusive=True)
        self._callbackQueue = result[0]
        self._channel.basic.consume(self._callbackQueue,
                                    self.onResponse,
                                    no_ack=True)
        self._response = None

    def onResponse(self, message):
        """On response
        """
        correlationID = message.properties.get('correlation_id')
        print 'Receive server response [%s] correlationID [%s]' % (
            message.body, correlationID)
        self._response = int(message.body)

    def call(self, number):
        """The call method
        """
        self._response = None
        corrID = str(uuid4())
        print 'Call server with request [%s] correlationID [%s]' % (number,
                                                                    corrID)
        self._channel.basic.publish(
            Message(str(number),
                    reply_to=self._callbackQueue,
                    correlation_id=corrID), '', 'test_rpc')
        while self._response is None:
            self._conn.read_frames()
        # Done
        return self._response
コード例 #27
0
ファイル: client.py プロジェクト: lipixun/pytest
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password)
        gevent.spawn(self.loop)
        self._channel = self._conn.channel()

    def loop(self):
        """The loop
        """
        while self._conn:
            self._conn.read_frames()
            gevent.sleep()

    def call(self):
        """The call method
        """
        self._channel.basic.publish(Message('A test body'), '', 'test_gevent')
コード例 #28
0
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password)
        gevent.spawn(self.loop)
        self._channel = self._conn.channel()
        self._channel.confirm.select()
        self._channel.basic.set_return_listener(self.onBasicReturn)
        self._channel.basic.set_ack_listener(self.onDeliverAck)
        self._channel.basic.set_nack_listener(self.onDeliverNAck)

    def loop(self):
        """The loop
        """
        while self._conn:
            self._conn.read_frames()
            gevent.sleep()

    def onBasicReturn(self, message):
        """On basic return
        """
        print 'Basic return message [%s]' % message

    def onDeliverAck(self, messageID):
        """On deliver ACK
        """
        print 'Deliver ACK [%s]' % messageID

    def onDeliverNAck(self, messageID, requeue):
        """On deliver nack
        """
        print 'Deliver NACK [%s] Requeue [%s]' % (messageID, requeue)

    def call(self, content, queue):
        """The call method
        """
        return self._channel.basic.publish(Message(content), '', queue)
コード例 #29
0
ファイル: client.py プロジェクト: lipixun/pytest
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
        self._channel = self._conn.channel()

    def call(self):
        """The call method
        """
        self._channel.basic.publish(Message('A test body', correlation_id = '123', application_headers = { 'custom_header': 'value', 'custom_header1': 1 }), '', 'test_meta')
コード例 #30
0
    def _connect_to_broker(self):
        ''' Connect to broker and regisiter cleanup action to disconnect

        :returns: connection instance
        :rtype: `haigha.connections.rabbit_connection.Connection`
        '''
        sock_opts = {
            (socket.IPPROTO_TCP, socket.TCP_NODELAY): 1,
        }
        connection = RabbitConnection(logger=_LOG,
                                      debug=_OPTIONS.debug,
                                      user=_OPTIONS.user,
                                      password=_OPTIONS.password,
                                      vhost=_OPTIONS.vhost,
                                      host=_OPTIONS.host,
                                      heartbeat=None,
                                      sock_opts=sock_opts,
                                      transport='socket')
        self.addCleanup(lambda: connection.close(disconnect=True)
                        if not connection.closed else None)

        return connection
コード例 #31
0
ファイル: rabbit_extensions_test.py プロジェクト: 3ddi/haigha
    def _connect_to_broker(self):
        ''' Connect to broker and regisiter cleanup action to disconnect

        :returns: connection instance
        :rtype: `haigha.connections.rabbit_connection.Connection`
        '''
        sock_opts = {
            (socket.IPPROTO_TCP, socket.TCP_NODELAY) : 1,
        }
        connection = RabbitConnection(
            logger=_LOG,
            debug=_OPTIONS.debug,
            user=_OPTIONS.user,
            password=_OPTIONS.password,
            vhost=_OPTIONS.vhost,
            host=_OPTIONS.host,
            heartbeat=None,
            sock_opts=sock_opts,
            transport='socket')
        self.addCleanup(lambda: connection.close(disconnect=True)
                        if not connection.closed else None)

        return connection
コード例 #32
0
ファイル: server.py プロジェクト: lipixun/pytest
class Server(object):
    """The RPC Server
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        self._channel = self._conn.channel()
        self._channel.queue.declare('test_rpc', auto_delete=True)
        self._channel.basic.consume('test_rpc', self.callee, no_ack=False)

    def run(self):
        """Waiting for response
        """
        while True:
            self._conn.read_frames()

    def callee(self, message):
        """The callee method
        """
        num = int(message.body)
        replyTo = message.properties.get('reply_to')
        correlationID = message.properties.get('correlation_id')
        deliveryTag = message.delivery_info.get('delivery_tag')
        # Print the meta
        print 'Receive message body [%s] replyTo [%s] correlationID [%s]' % (
            num, replyTo, correlationID)
        # Return add 1
        self._channel.basic.publish(
            Message(str(num + 1), correlation_id=correlationID), '', replyTo)
        # ACK
        self._channel.basic.ack(deliveryTag)
コード例 #33
0
    def __init__(self, connectionParams=None, channelConfigCb=None):
        """
    NOTE: Connection establishment may be performed in the scope of the
    constructor or on demand, depending on the underlying implementation

    :param nta.utils.amqp.connection.ConnectionParams connectionParams:
      parameters for connecting to AMQP broker;
      [default=default params for RabbitMQ broker on localhost]
    :param channelConfigCb: An optional callback function that will be
      called whenever a new AMQP Channel is being brought up
    :type channelConfigCb: None or callable with the signature
      channelConfigCb(SynchronousAmqpClient)
    """
        self._channelConfigCb = channelConfigCb

        # Holds _ChannelContext when channel is created; we create the channel on
        # demand. The implementation accesses this member via the
        # `_liveChannelContext` property getter when it's desirable to bring up the
        # channel on-on demand. When it's undesirable to bring up the channel, the
        # implementation interacts directly with this member, which will be None
        # when we don't have a channel.
        self._channelContextInstance = None

        # Set to True when user calls close, so we know to not raise an exception
        # from our _on*Closed callback methods
        self._userInitiatedClosing = False

        # Instantiate underlying connection object
        params = connectionParams if connectionParams is not None else amqp_connection.ConnectionParams()

        # NOTE: we could get a `close_cb` call from RabbitConnection constructor, so
        # prepare for it by initializing `self._connection`
        self._connection = None
        self._connection = RabbitConnection(
            transport="socket",
            sock_opts={(socket.IPPROTO_TCP, socket.TCP_NODELAY): 1},
            synchronous=True,
            close_cb=self._onConnectionClosed,
            user=params.credentials.username,
            password=params.credentials.password,
            vhost=params.vhost,
            host=params.host,
            port=params.port,
            heartbeat=self._DEFAULT_HEARTBEAT_TIMEOUT_SEC,
            logger=g_log,
        )
コード例 #34
0
ファイル: client.py プロジェクト: UPCnet/maxcarrot
    def connect(self, url):
        """
            Connect to rabbitmq and create a channel
        """
        parts = re.search(r'amqp://(\w+):(\w+)@([^\:]+)\:(\d+)\/(.*)\/?', url).groups()
        self.user, self.password, self.host, self.port, self.vhost_url = parts
        self.vhost = self.vhost_url.replace('%2F', '/')

        params = dict(
            user=self.user, password=self.password,
            vhost=self.vhost, host=self.host, transport=self.transport
        )
        if self.transport == 'gevent':
            params['close_cb'] = self._connection_closed_cb,

        self.connection = RabbitConnection(**params)

        self.ch = self.connection.channel()
        if self.transport == 'gevent':
            self._message_pump_greenlet = gevent.spawn(self._message_pump_greenthread)
            self.ch.add_close_listener(self._channel_closed_cb)
コード例 #35
0
ファイル: haighamq.py プロジェクト: threathunterX/python_lib
def get_connection(amqp_url):
    global connection
    if connection and not connection.closed:
        return connection

    parse = urlparse.urlparse(amqp_url)
    sock_opts = {
        (socket.IPPROTO_TCP, socket.TCP_NODELAY): 1
        }
    connection = RabbitConnection(logger=logger, debug=logging.WARN, user=parse.username, password=parse.password,
                                   vhost=parse.path, host=parse.hostname, hearbeat=None, port=parse.port,
                                   close_cb=connection_closed, sock_opts=sock_opts, transport="gevent")

    global connection_task
    connection_task = gevent.spawn(frame_loop)

    global connection_consumers
    if connection_consumers:
        for c in connection_consumers.itervalues():
            c._reconnect()
            c.start_consuming()
    return connection
コード例 #36
0
class Client(object):
    """The RPC Client
    """
    def __init__(self, host, port, vhost, user, password):
        """Create a new Server
        """
        self._conn = RabbitConnection(host=host,
                                      port=port,
                                      vhost=vhost,
                                      user=user,
                                      password=password)
        self._channel = self._conn.channel()

    def call(self):
        """The call method
        """
        self._channel.basic.publish(
            Message('A test body',
                    correlation_id='123',
                    application_headers={
                        'custom_header': 'value',
                        'custom_header1': 1
                    }), '', 'test_meta')
コード例 #37
0
class SynchronousAmqpClient(object):
    """Synchronous (blocking) AMQP client abstraction that exposes AMQP
  functionality presently needed by nta.utils and products. New AMQP
  functionality will be exposed as the need arises.

  This class provides a consistent AMQP client API to the rest of the products
  regardless of the underlying implementation. This helps avoid/minimize changes
  to the higher-level code when we need to swap out the underlying client
  implementation.

  This class is NOT the place for higher-level constructs: see
  message_bus_connector module for an example of higher-level functionality
  built on top of this class.

  NOTE: this implementation is completely synchronous and MUST NOT expose
  callbacks (callbaks lead to complexities, such as an opportunity for
  unintended/unsupported recursion)

  NOTE: The `no*` parameters, such as `noLocal` and `noAck`, are artificats
  of the AMQP protocol specification. The author of SynchronousAmqpClient chose
  to preserve those semantics to facilitate better correlation with AMQP
  documentation.
  """

    # Correlations between names of BasicProperties attributes and Haigha's
    # message property names.
    #
    # The table consists of the tollowing columns
    #     BasicProperty attribute name
    #     Corresponding Haigha property name
    #     Value conversion function from BasicProperty to Haigha
    #     Value conversion function from Haigha to BasicProperty
    #
    _asIs = lambda x: x
    _PROPERTY_CORRELATIONS = (
        ("contentType", "content_type", _asIs, _asIs),
        ("contentEncoding", "content_encoding", _asIs, _asIs),
        ("headers", "application_headers", _asIs, _asIs),
        ("deliveryMode", "delivery_mode", _asIs, _asIs),
        ("priority", "priority", _asIs, _asIs),
        ("correlationId", "correlation_id", _asIs, _asIs),
        ("replyTo", "reply_to", _asIs, _asIs),
        ("expiration", "expiration", _asIs, _asIs),
        ("messageId", "message_id", _asIs, _asIs),
        ("timestamp", "timestamp", datetime.utcfromtimestamp, epochFromNaiveUTCDatetime),
        ("messageType", "type", _asIs, _asIs),
        ("userId", "user_id", _asIs, _asIs),
        ("appId", "app_id", _asIs, _asIs),
        ("clusterId", "cluster_id", _asIs, _asIs),
    )

    # haigha returns body as bytearray, but our current users of the interface
    # assume they are getting str or bytes
    _decodeMessageBody = str

    # NOTE: RabbitMQ release 3.5.5, changed the server's default heartbeat timeout
    # from 580 to 60, causing frequent dropped connections on our blocking
    # transport. So, we restore the longer timeout by passing a bigger value
    # to the broker during connection tuning.
    _DEFAULT_HEARTBEAT_TIMEOUT_SEC = 600

    def __init__(self, connectionParams=None, channelConfigCb=None):
        """
    NOTE: Connection establishment may be performed in the scope of the
    constructor or on demand, depending on the underlying implementation

    :param nta.utils.amqp.connection.ConnectionParams connectionParams:
      parameters for connecting to AMQP broker;
      [default=default params for RabbitMQ broker on localhost]
    :param channelConfigCb: An optional callback function that will be
      called whenever a new AMQP Channel is being brought up
    :type channelConfigCb: None or callable with the signature
      channelConfigCb(SynchronousAmqpClient)
    """
        self._channelConfigCb = channelConfigCb

        # Holds _ChannelContext when channel is created; we create the channel on
        # demand. The implementation accesses this member via the
        # `_liveChannelContext` property getter when it's desirable to bring up the
        # channel on-on demand. When it's undesirable to bring up the channel, the
        # implementation interacts directly with this member, which will be None
        # when we don't have a channel.
        self._channelContextInstance = None

        # Set to True when user calls close, so we know to not raise an exception
        # from our _on*Closed callback methods
        self._userInitiatedClosing = False

        # Instantiate underlying connection object
        params = connectionParams if connectionParams is not None else amqp_connection.ConnectionParams()

        # NOTE: we could get a `close_cb` call from RabbitConnection constructor, so
        # prepare for it by initializing `self._connection`
        self._connection = None
        self._connection = RabbitConnection(
            transport="socket",
            sock_opts={(socket.IPPROTO_TCP, socket.TCP_NODELAY): 1},
            synchronous=True,
            close_cb=self._onConnectionClosed,
            user=params.credentials.username,
            password=params.credentials.password,
            vhost=params.vhost,
            host=params.host,
            port=params.port,
            heartbeat=self._DEFAULT_HEARTBEAT_TIMEOUT_SEC,
            logger=g_log,
        )

    def __repr__(self):
        # NOTE: we don't use the _liveChannelContext property getter in order to
        # avoid creation of channel here
        return "%s(channelContext=%r)" % (self.__class__.__name__, self._channelContextInstance)

    @property
    def _liveChannelContext(self):
        """NOTE: Creates channel on demand"""
        if self._channelContextInstance is None:
            self._channelContextInstance = _ChannelContext(self._connection.channel(synchronous=True))
            try:
                self._channelContextInstance.channel.add_close_listener(self._onChannelClosed)

                self._channelContextInstance.channel.basic.set_return_listener(self._onMessageReturn)

                if self._channelConfigCb is not None:
                    self._channelConfigCb(self)
            except Exception:  # pylint: disable=W0703
                g_log.exception("Channel configuration failed")
                try:
                    # Preserve the original exception
                    raise
                finally:
                    # Close channel and reset channel context
                    try:
                        if self._channelContextInstance is not None:
                            self._channelContextInstance.channel.close(disconnect=True)
                    except Exception:  # pylint: disable=W0703
                        # Suppress the secondary exception from cleanup
                        g_log.exception("Channel closing Failed following configuration failure")
                    finally:
                        self._channelContextInstance.reset()
                        self._channelContextInstance = None

        return self._channelContextInstance

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def isOpen(self):
        return self._connection is not None and not self._connection.closed

    def close(self):
        """Gracefully close client"""
        self._userInitiatedClosing = True
        try:
            # NOTE: we check _channelContextInstance directly to avoid creating a
            # channel if one doesn't exist
            if self._channelContextInstance is not None:
                channelContext = self._channelContextInstance
                try:
                    channelContext.channel.close()
                except Exception:  # pylint: disable=W0703
                    g_log.exception("Channel close failed")

            if self._connection is not None:
                try:
                    self._connection.close(disconnect=True)
                except Exception:  # pylint: disable=W0703
                    g_log.exception("Connection close failed")
        finally:
            self._connection = None
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None

    def enablePublisherAcks(self):
        """Enable RabbitMQ publisher acknowledgments

    :raises nta.utils.amqp.exceptions.UnroutableError: raised when messages
      that were sent in non-publisher-acknowledgments mode are returned by
      the time the Confirm.Select-Ok is received
    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        channelContext = self._liveChannelContext

        if channelContext.pubacksSelected:
            g_log.warning("enablePublisherAcks: already enabled")
        else:
            channelContext.channel.confirm.select(nowait=False)
            channelContext.pubacksSelected = True

            # NOTE: Unroutable messages returned after this will be in the context of
            # publisher acknowledgments
            self._raiseAndClearIfReturnedMessages()

    def publish(self, message, exchange, routingKey, mandatory=False):
        """ Publish a message

    :param nta.utils.amqp.messages.Message message:
    :param str exchange: destination exchange name; "" for default exchange
    :param str routingKey: Message routing key
    :param bool mandatory: This flag tells the server how to react if the
      message cannot be routed to a queue. If this flag is True, the server will
      return an unroutable message with a Return method. If this flag is False
      the server silently drops the message.

    :raises nta.utils.amqp.exceptions.UnroutableError: when in
      non-publisher-acknowledgments mode, raised before attempting to publish
      given message if unroutable messages had been returned. In
      publisher-acknowledgments mode, raised if the given
      message is returned as unroutable.
    :raises nta.utils.amqp.exceptions.NackError: when the given message is
      NACKed by broker while channel is in RabbitMQ publisher-acknowledgments
      mode
    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        message = HaighaMessage(body=message.body, **self._makeHaighaPropertiesDict(message.properties))

        channelContext = self._liveChannelContext

        if channelContext.pubacksSelected:
            # In publisher-acknowledgments mode
            assert not channelContext.returnedMessages, (
                len(channelContext.returnedMessages),
                channelContext.returnedMessages,
            )

            pubackState = _PubackState()
            channelContext.channel.basic.set_ack_listener(pubackState.handleAck)
            channelContext.channel.basic.set_nack_listener(pubackState.handleNack)

            deliveryTag = channelContext.channel.basic.publish(
                message, exchange=exchange, routing_key=routingKey, mandatory=mandatory
            )

            # Wait for ACK or NACK
            while not pubackState.ready:
                self._connection.read_frames()

            try:
                ((how, responseTag),) = pubackState.values
            except ValueError:
                g_log.exception("Error unpacking values=%r", pubackState.values)
                raise

            assert responseTag == deliveryTag, ((how, responseTag), deliveryTag)

            if how == _PubackState.NACK:
                # Raise NackError with returned message
                returnedMessages = channelContext.returnedMessages
                channelContext.returnedMessages = []

                raise amqp_exceptions.NackError(returnedMessages)

            # It was Acked
            assert how == _PubackState.ACK, how

            # Raise if this message was returned as unroutable
            self._raiseAndClearIfReturnedMessages()

        else:
            # Not in publisher-acknowledgments mode

            # Raise if some prior messages were returned as unroutable
            self._raiseAndClearIfReturnedMessages()

            channelContext.channel.basic.publish(
                message, exchange=exchange, routing_key=routingKey, mandatory=mandatory
            )

    def requestQoS(self, prefetchSize=0, prefetchCount=0, entireConnection=False):
        """This method requests a specific quality of service. The QoS can be
    specified for the current channel or for all channels on the connection. The
    particular properties and semantics of a qos method always depend on the
    content class semantics

    :param int prefetchSize: The client can request that messages be sent in
      advance so that when the client finishes processing a message, the
      following message is already held locally, rather than needing to be sent
      down the channel. Prefetching gives a performance improvement. This field
      specifies the prefetch window size in octets. The server will send a
      message in advance if it is equal to or smaller in size than the available
      prefetch size (and also falls into other prefetch limits). May be set to
      zero, meaning "no specific limit", although other prefetch limits may
      still apply. The prefetchsize is ignored if the no-ack option is set.
    :param int prefetchCount: Specifies a prefetch window in terms of whole
      messages. This field may be used in combination with the prefetch-size
      field; a message will only be sent in advance if both prefetch windows
      (and those at the channel and connection level) allow it. The
      prefetch-count is ignored if the no-ack option is set.
    :param bool entireConnection: By default the QoS settings apply to the
      current channel only. If this field is set, they are applied to the entire
      connection.

    :raises AmqpChannelError:
    """
        self._liveChannelContext.channel.basic.qos(
            prefetch_size=prefetchSize, prefetch_count=prefetchCount, is_global=entireConnection
        )

    def createConsumer(self, queue, noLocal=False, noAck=False, exclusive=False):
        """This method asks the server to start a "consumer", which is a transient
    request for messages from a specific queue. Consumers last as long as the
    channel they were declared on, or until the client or broker cancels them.
    See `Consumer.cancel()`

    Use `getNextEvent()` to retrieve consumed messages and other events.

    :param str queue: name of the queue to consume from
    :param bool noLocal: If true, the server will not send messages to the
      connection that published them.
    :param bool noAck: if true, the broker will not expect messages to be ACKed
    :param bool exclusive: Request exclusive consumer access, meaning only this
      consumer can access the queue

    :returns: consumer context
    :rtype: nta.utils.amqp.consumer.Consumer

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    :raises nta.utils.amqp.exceptions.AmqpConnectionError:
    """
        consumerTag = self._makeConsumerTag()

        channelContext = self._liveChannelContext

        channelContext.channel.basic.consume(
            queue,
            consumer=self._onMessageDelivery,
            consumer_tag=consumerTag,
            no_local=noLocal,
            no_ack=noAck,
            exclusive=exclusive,
            cancel_cb=self._onConsumerCancelled,
            nowait=False,
        )

        channelContext.consumerSet.add(consumerTag)

        consumer = amqp_consumer.Consumer(tag=consumerTag, queue=queue, cancelImpl=channelContext.cancelConsumer)

        g_log.info(
            "Created consumer=%r; queue=%r, noLocal=%r, noAck=%r, exclusive=%r",
            consumer,
            queue,
            noLocal,
            noAck,
            exclusive,
        )

        return consumer

    def hasEvent(self):
        """Check if there are events ready for consumption. See `getNextEvent()`.

    :returns: True if there is at least one event ready for consumption, in
      which case `getNextEvent()` may be called once without blocking.
    :rtype: bool
    """
        channelContext = self._channelContextInstance
        return bool(channelContext is not None and channelContext.pendingEvents)

    def getNextEvent(self):
        """Get next event, blocking if there isn't one yet. See `hasEvent()`. You
    MUST have an active consumer (`createConsumer`) or other event source before
    calling this method.

    An event may be an object of one of the following classes:

      nta.utils.amqp.messages.ConsumerMessage
      nta.utils.amqp.consumer.ConsumerCancellation

    :returns: the next event when it becomes available

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        # We expect the context to be set up already
        channelContext = self._channelContextInstance

        while not channelContext.pendingEvents:
            self._connection.read_frames()

        return channelContext.pendingEvents.popleft()

    def readEvents(self):
        """Generator that yields results of `getNextEvent()`"""
        while True:
            yield self.getNextEvent()

    def getOneMessage(self, queue, noAck=False):
        """This is the polling, less-performant method of getting a message. This
    method provides a direct access to the messages in a queue using a
    synchronous dialogue that is designed for specific types of application
    where synchronous functionality is more important than performance.

    :param str queue: name of the queue to get a message from
    :param bool noAck: if true, the broker will not be expecting an Ack

    :returns: A PolledMessage object if there was a message in queue; None if
      there was no message in queue.
    :rtype: PolledMessage or None

    :raises AmqpChannelError:
    """
        channelContext = self._liveChannelContext

        consumer = _CallbackSink()

        channelContext.channel.basic.get(queue, consumer=consumer, no_ack=noAck)
        while not consumer.ready:
            self._connection.read_frames()

        try:
            ((message,),) = consumer.values
        except ValueError:
            g_log.exception("Error unpacking values=%r", consumer.values)
            raise

        if message is not None:
            ackImpl = channelContext.ack if not noAck else None
            nackImpl = channelContext.nack if not noAck else None
            message = self._makePolledMessage(message, ackImpl, nackImpl)

        return message

    @classmethod
    def _makePolledMessage(cls, haighaMessage, ackImpl, nackImpl):
        """Make PolledMessage from haigha message retrieved via Basic.Get

    :param haigha.message.Message haighaMessage: haigha message retrieved via
      Basic.Get
    :param ackImpl: callable for acking the message that has the following
      signature: ackImpl(deliveryTag, multiple=False); or None
    :param nackImpl: callable for nacking the message that has the following
      signature: nackImpl(deliveryTag, requeue); or None

    :rtype: nta.utils.amqp.messages.PolledMessage
    """
        info = haighaMessage.delivery_info

        methodInfo = amqp_messages.MessageGetInfo(
            deliveryTag=info["delivery_tag"],
            redelivered=bool(info["redelivered"]),
            exchange=info["exchange"],
            routingKey=info["routing_key"],
            messageCount=info["message_count"],
        )

        return amqp_messages.PolledMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo,
            ackImpl=ackImpl,
            nackImpl=nackImpl,
        )

    def recover(self, requeue=False):
        """This method asks the server to redeliver all unacknowledged messages on a
    specified channel. Zero or more messages may be redelivered.

    NOTE: RabbitMQ does not currently support recovering with requeue=False

    :param bool requeue: If false, the message will be redelivered to the
      original recipient. If true, the server will attempt to requeue the
      message, potentially then delivering it to an alternative subscriber.
    """
        self._liveChannelContext.channel.basic.recover(requeue=requeue)

    def ackAll(self):
        """Acknowledge all unacknowledged messages on current channel instance.

    Acknowledgemets related to specific messages are performed via the message's
    own `ack()` method.

    NOTE: messages received prior to the AmqpChannelError exception cannot be
    acknowledged since that exception occurs after the AMQP channel is closed
    """
        self._channelContextInstance.ack(deliveryTag=0, multiple=True)

    def nackAll(self, requeue=False):
        """Reject all outstanding (unacknowledged) messages on current channel
    instance.

    Rejections related to specific messages are performed via the message's
    own `nack()` method.

    NOTE: has no impact on messages received prior to the AmqpChannelError
    exception since AmqpChannelError is raised after the AMQP channel is closed

    :param bool requeue: If requeue is true, the server will attempt to requeue
      the messages. If requeue is false or the requeue attempt fails the
      messages are discarded or dead-lettered
    """
        self._channelContextInstance.nack(deliveryTag=0, multiple=True, requeue=requeue)

    def declareExchange(self, exchange, exchangeType, passive=False, durable=False, autoDelete=False, arguments=None):
        """Declare an exchange

    :param str exchange: name of the exchange
    :param str exchangeType: type of the exchange
    :param bool passive: If True, the server will reply with Declare-Ok if the
      exchange already exists with the same name, and raise an error if not. The
      client can use this to check whether an exchange exists without modifying
      the server state. When set, all other method fields except name are
      ignored. Arguments are compared for semantic equivalence.
    :param bool durable: If True when creating a new exchange, the exchange will
      be marked as durable. Durable exchanges remain active when a server
      restarts. Non-durable exchanges (transient exchanges) are purged if/when a
      server restarts.
    :param bool autoDelete: If true, the exchange is deleted when all queues
      have finished using it (RabbitMQ-specific).
    :param dict arguments: custom key/value pairs for the exchange

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.exchange.declare(
            exchange,
            exchangeType,
            passive=passive,
            durable=durable,
            auto_delete=autoDelete,
            arguments=arguments or dict(),
            nowait=False,
        )

    def deleteExchange(self, exchange, ifUnused=False):
        """Delete an exchange

    :param str exchange: exchange to be deleted
    :param bool ifUnused: If True, the server will only delete the exchange if
      it has no queue bindings. If the exchange has queue bindings the server
      does not delete it but raises a channel exception instead.

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.exchange.delete(exchange, if_unused=ifUnused, nowait=False)

    def declareQueue(self, queue, passive=False, durable=False, exclusive=False, autoDelete=False, arguments=None):
        """Declare a queue

    :param str queue: name of queue
    :param bool passive: If True, the server will reply with Declare-Ok if the
      queue already exists with the same name, and raise an error if not. The
      client can use this to check whether a queue exists without modifying the
      server state. When set, all other method fields except name are ignored.
      Arguments are compared for semantic equivalence.
    :param bool durable: If true when creating a new queue, the queue will be
      marked as durable. Durable queues remain active when a server restarts.
      Non-durable queues (transient queues) are purged if/when a server
      restarts. Note that durable queues do not necessarily hold persistent
      messages, although it does not make sense to send persistent messages to a
      transient queue.
    :param bool exclusive: Exclusive queues may only be accessed by the current
      connection, and are deleted when that connection closes. Passive
      declaration of an exclusive queue by other connections are not allowed.
    :param bool autoDelete: If true, the queue is deleted when all consumers
      have finished using it. The last consumer can be cancelled either
      explicitly or because its channel is closed. If there was no consumer ever
      on the queue, it won't be deleted. Applications can explicitly delete
      auto-delete queues using the Delete method as normal. (RabbitMQ-specific)
    :param dict arguments: A set of key/value pairs for the declaration. The
      syntax and semantics of these arguments depends on the server
      implementation.

    :rtype: nta.utils.amqp.queue.QueueDeclarationResult

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        queue, messageCount, consumerCount = self._liveChannelContext.channel.queue.declare(
            queue,
            passive=passive,
            durable=durable,
            exclusive=exclusive,
            auto_delete=autoDelete,
            arguments=arguments or dict(),
            nowait=False,
        )

        return amqp_queue.QueueDeclarationResult(queue, messageCount, consumerCount)

    def deleteQueue(self, queue, ifUnused=False, ifEmpty=False):
        """Delete a queue. When a queue is deleted any pending messages are sent to
    a dead-letter queue if this is defined in the server configuration, and all
    consumers on the queue are cancelled

    :param str queue: name of the queue to delete
    :param bool ifUnused: If true, the server will only delete the queue if it
      has no consumers. If the queue has consumers the server does does not
      delete it but raises a channel exception instead.
    :param bool ifEmpty: If true, the server will only delete the queue if it
      has no messages

    :returns: number of messages deleted
    :rtype: int

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        return self._liveChannelContext.channel.queue.delete(queue, if_unused=ifUnused, if_empty=ifEmpty, nowait=False)

    def purgeQueue(self, queue):
        """Remove all messages from a queue which are not awaiting acknowledgment.

    :param str queue: name of the queue to purge

    :returns: number of messages purged
    :rtype: int

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        return self._liveChannelContext.channel.queue.purge(queue, nowait=False)

    def bindQueue(self, queue, exchange, routingKey, arguments=None):
        """Bind a queue to an exchange

    :param str queue: name of the queue to bind
    :param str exchange: name of the exchange to bind to
    :param str routingKey: Specifies the routing key for the binding. The
      routing key is used for routing messages depending on the exchange
      configuration. Not all exchanges use a routing key refer to the
      specific exchange documentation. If the queue name is empty, the server
      uses the last queue declared on the channel. If the routing key is also
      empty, the server uses this queue name for the routing key as well. If the
      queue name is provided but the routing key is empty, the server does the
      binding with that empty routing key. The meaning of empty routing keys
      depends on the exchange implementation.
    :param dict arguments: A set of key/value pairs for the binding. The syntax
      and semantics of these arguments depends on the exchange class and server
      implemenetation.

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.queue.bind(
            queue=queue, exchange=exchange, routing_key=routingKey, arguments=arguments or dict(), nowait=False
        )

    def unbindQueue(self, queue, exchange, routingKey, arguments=None):
        """Unbind a queue fro an exchange

    :param str queue: name of the queue to unbind
    :param str exchange: name of the exchange to unbind from
    :param str routingKey: the routing key of the binding to unbind
    :param dict arguments: Specifies the arguments of the binding to unbind

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.queue.unbind(
            queue=queue, exchange=exchange, routing_key=routingKey, arguments=arguments or dict()
        )

    def _raiseAndClearIfReturnedMessages(self):
        """If returned messages are present, raise UnroutableError and clear
    returned messages holding buffer

    :raises nta.utils.amqp.exceptions.UnroutableError: if returned messages
      are present
    """
        channelContext = self._channelContextInstance

        if channelContext and channelContext.returnedMessages:
            messages = channelContext.returnedMessages
            channelContext.returnedMessages = []
            raise amqp_exceptions.UnroutableError(messages)

    @classmethod
    def _makeHaighaPropertiesDict(cls, BasicProperties):
        """Marshal BasicProperties into the haigha properties dict

    :param nta.utils.amqp.messages.BasicProperties BasicProperties:

    :returns: dict of Properties expected by Haigha's publish method
    :rtype: dict
    """
        props = dict()

        for attrName, propName, clientToHaigha, _ in cls._PROPERTY_CORRELATIONS:
            value = getattr(BasicProperties, attrName)
            # Add only those properties that have concrete values
            if value is not None:
                props[propName] = clientToHaigha(value)

        return props

    @classmethod
    def _makeBasicProperties(cls, haighaProperties):
        attributes = dict()

        for attrName, propName, _, haighaToClient in cls._PROPERTY_CORRELATIONS:
            value = haighaProperties.get(propName)

            if value is not None:
                value = haighaToClient(value)

            attributes[attrName] = value

        return amqp_messages.BasicProperties(**attributes)

    def _makeConsumerTag(self):
        channelContext = self._liveChannelContext

        tag = "channel-%d-%d" % (channelContext.channel.channel_id, channelContext.nextConsumerTag)
        channelContext.nextConsumerTag += 1
        return tag

    def _onMessageDelivery(self, message):
        """Handle consumer message from Basic.Deliver

    :param haigha.message.Message message:
    """
        channelContext = self._channelContextInstance

        g_log.debug("Consumer message received: %.255s", message)
        channelContext.pendingEvents.append(self._makeConsumerMessage(message, channelContext.ack, channelContext.nack))

    @classmethod
    def _makeConsumerMessage(cls, haighaMessage, ackImpl, nackImpl):
        """Make ConsumerMessage from haigha message received via Basic.Deliver

    :param haigha.message.Message haighaMessage: haigha message received via
      Basic.Deliver
    :param ackImpl: callable for acking the message that has the following
      signature: ackImpl(deliveryTag, multiple=False); or None
    :param nackImpl: callable for nacking the message that has the following
      signature: nackImpl(deliveryTag, requeue); or None

    :rtype: ConsumerMessage
    """
        info = haighaMessage.delivery_info

        methodInfo = amqp_messages.MessageDeliveryInfo(
            consumerTag=info["consumer_tag"],
            deliveryTag=info["delivery_tag"],
            redelivered=bool(info["redelivered"]),
            exchange=info["exchange"],
            routingKey=info["routing_key"],
        )

        return amqp_messages.ConsumerMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo,
            ackImpl=ackImpl,
            nackImpl=nackImpl,
        )

    def _onConsumerCancelled(self, consumerTag):
        """Handle notification of Basic.Cancel from broker

    :param str consumerTag: tag of consumer cancelled by broker
    """
        channelContext = self._channelContextInstance

        channelContext.pendingEvents.append(amqp_consumer.ConsumerCancellation(consumerTag))

        channelContext.consumerSet.discard(consumerTag)

    def _onMessageReturn(self, message):
        """Handle unroutable message returned by broker

    NOTE: this may happen regardless of RabbitMQ-specific puback mode; however,
    if it's going to happen in puback mode, RabbitMQ guarantees that it will
    take palce *before* Basic.Ack

    :param haigha.message.Message message:
    """
        g_log.warning("Message returned: %.255s", message)

        self._channelContextInstance.returnedMessages.append(self._makeReturnedMessage(message))

    @classmethod
    def _makeReturnedMessage(cls, haighaMessage):
        """
    :param haigha.message.Message haighaMessage: haigha message returned via
      Basic.Return

    :rtype: nta.utils.amqp.messages.ReturnedMessage
    """
        info = haighaMessage.return_info

        methodInfo = amqp_messages.MessageReturnInfo(
            replyCode=info["reply_code"],
            replyText=info["reply_text"],
            exchange=info["exchange"],
            routingKey=info["routing_key"],
        )

        return amqp_messages.ReturnedMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo,
        )

    @staticmethod
    def _amqpErrorArgsFromCloseInfo(closeInfo):
        """
    :param dict closeInfo: channel or connection close_info from Haigha

    :returns: a dict with property names compatible with _AmqpErrorBase
      constructor args
    """
        return dict(
            code=closeInfo["reply_code"],
            text=closeInfo["reply_text"],
            classId=closeInfo["class_id"],
            methodId=closeInfo["method_id"],
        )

    def _onConnectionClosed(self):
        try:
            if self._connection is None:
                # Failure during connection setup
                raise amqp_exceptions.AmqpConnectionError(code=0, text="connection setup failed", classId=0, methodId=0)

            closeInfo = self._connection.close_info

            if self._userInitiatedClosing:
                if closeInfo["reply_code"] != 0:
                    raise amqp_exceptions.AmqpConnectionError(**self._amqpErrorArgsFromCloseInfo(closeInfo))
            else:
                raise amqp_exceptions.AmqpConnectionError(**self._amqpErrorArgsFromCloseInfo(closeInfo))
        finally:
            self._connection = None
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None

    def _onChannelClosed(self, channel):
        try:
            closeInfo = channel.close_info

            if self._userInitiatedClosing:
                if closeInfo["reply_code"] != 0:
                    raise amqp_exceptions.AmqpChannelError(**self._amqpErrorArgsFromCloseInfo(closeInfo))
            else:
                raise amqp_exceptions.AmqpChannelError(**self._amqpErrorArgsFromCloseInfo(closeInfo))
        finally:
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None
コード例 #38
0
ファイル: publish.py プロジェクト: seatgeek/cronq
import json
import os
import time

from haigha.connections.rabbit_connection import RabbitConnection
from haigha.message import Message

connection = RabbitConnection(
    user=os.getenv('RABBITMQ_USER'),
    password=os.getenv('RABBITMQ_PASS'),
    vhost='/',
    host=os.getenv('RABBITMQ_HOSTS', 'localhost').split(',')[0],
    heartbeat=None,
    debug=True)

ch = connection.channel()
ch.exchange.declare('cronq', 'direct')
ch.queue.declare('cronq_jobs', auto_delete=False)
ch.queue.declare('cronq_results', auto_delete=False)
ch.queue.bind('cronq_jobs', 'cronq', 'cronq_jobs')
ch.queue.bind('cronq_results', 'cronq', 'cronq_results')

while True:
    print 'publish'
    cmd = {
        "cmd": "sleep 1",
        "job_id": 1024,
        "name": "[TEST] A test job",
        "run_id": "1234"
    }
    ch.basic.publish(
コード例 #39
0
ファイル: client.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(transport = 'gevent', host = host, port = port, vhost = vhost, user = user, password = password)
     gevent.spawn(self.loop)
     self._channel = self._conn.channel()
コード例 #40
0
ファイル: client.py プロジェクト: UPCnet/maxcarrot
class RabbitClient(object):
    """
        Wraps features defined in the rabbit max architecture
        resources specs defines rules to check exchanges and queues
        in order to declare them or delete on cleanups

        * Internal queues definitions are marked as native, to avoid deletion
        * Exchanges and queues that need to be created always are marked as global

    """

    __client_properties__ = {
        'library': 'haigha',
        'library-version': pkg_resources.require('haigha')[0].version
    }

    resource_specs = {
        'exchanges': [
            {'name': 'conversations', 'spec': 'conversations', 'type': 'topic'},
            {'name': 'twitter', 'spec': 'twitter', 'type': 'fanout'},
            {'name': 'syncacl', 'spec': 'syncacl', 'type': 'fanout'},
            {'name': 'activity', 'spec': 'activity', 'type': 'topic'},
            {'name': 'user_subscribe', 'spec': '.*?.subscribe', 'type': 'fanout', 'global': False},
            {'name': 'user_publish', 'spec': '.*?.publish', 'type': 'topic', 'global': False},
            {'name': 'default', 'spec': '^$', 'type': 'direct', 'native': True},
            {'name': 'internal', 'spec': 'amq\..*?', 'type': '.*', 'native': True},
        ],
        'queues': [
            {'name': 'dynamic', 'spec': 'amq\..*?', 'native': True, 'durable': False, 'auto_delete': True},
            {'name': 'messages', 'spec': 'messages', 'bindings': [
                {'exchange': 'conversations', 'routing_key': '*.messages'}
            ]},
            {'name': 'push', 'spec': 'push', 'bindings': [
                {'exchange': 'conversations', 'routing_key': '*.notifications'},
                {'exchange': 'activity', 'routing_key': '#'}
            ]},
            {'name': 'twitter', 'spec': 'twitter', 'bindings': [
                {'exchange': 'twitter'}
            ]},
            {'name': 'syncacl', 'spec': 'syncacl', 'bindings': [
                {'exchange': 'syncacl'}
            ]},
            {'name': 'tweety_restart', 'spec': 'tweety_restart'},
            {'name': 'twitter', 'spec': 'twitter'},
        ]
    }

    def __init__(self, url, declare=False, user=None, client_properties={}, transport='socket'):
        self.__client_properties__.update(client_properties)
        self.transport = transport

        # Fallback to socket transport if gevent not available
        if self.transport == 'gevent' and not gevent_available:
            self.transport = 'socket'

        self.connect(url)
        if declare:
            self.declare()

        self.exchange_specs_by_name = {spec['name']: spec for spec in self.resource_specs['exchanges']}
        self.queue_specs_by_name = {spec['name']: spec for spec in self.resource_specs['queues']}

        # Wrapper to interact with conversations
        self.conversations = RabbitConversations(self)
        self.activity = RabbitActivity(self)
        self.management = RabbitManagement(self, 'http://{}:15672/api'.format(self.host), self.vhost_url, self.user, self.password)

        if user is not None:
            self.bind(user)

    def spec_by_name(self, type, name):
        for spec in self.resource_specs[type]:
            if spec['name'] == name:
                return spec
        return None

    def connect(self, url):
        """
            Connect to rabbitmq and create a channel
        """
        parts = re.search(r'amqp://(\w+):(\w+)@([^\:]+)\:(\d+)\/(.*)\/?', url).groups()
        self.user, self.password, self.host, self.port, self.vhost_url = parts
        self.vhost = self.vhost_url.replace('%2F', '/')

        params = dict(
            user=self.user, password=self.password,
            vhost=self.vhost, host=self.host, transport=self.transport
        )
        if self.transport == 'gevent':
            params['close_cb'] = self._connection_closed_cb,

        self.connection = RabbitConnection(**params)

        self.ch = self.connection.channel()
        if self.transport == 'gevent':
            self._message_pump_greenlet = gevent.spawn(self._message_pump_greenthread)
            self.ch.add_close_listener(self._channel_closed_cb)

    def _message_pump_greenthread(self):
        try:
            while self.connection is not None:
                # Pump
                self.connection.read_frames()

                # Yield to other greenlets so they don't starve
                gevent.sleep()
        finally:
            return

    def _channel_closed_cb(self, ch):
        self.ch = None
        self.connection.close()
        return

    def _connection_closed_cb(self):
        self.connection = None

    def disconnect(self):
        """
            Disconnecto from rabbitmq
        """
        self.connection.close()

    def declare(self):
        """
            Create all defined exchanges and queues on rabbit.
            Ignore those marked as internal or not global
        """
        for exchange in self.resource_specs['exchanges']:
            if exchange.get('global', True) and not exchange.get('native', False):
                self.ch.exchange.declare(
                    exchange=exchange['name'],
                    type=exchange['type'],
                    durable=True,
                    auto_delete=False
                )

        for queue in self.resource_specs['queues']:
            if queue.get('global', True) and not queue.get('native', False):
                self.ch.queue.declare(
                    queue=queue['name'],
                    durable=True,
                    auto_delete=False
                )
                for binding in queue.get('bindings', []):
                    self.ch.queue.bind(
                        queue=queue['name'],
                        exchange=binding['exchange'],
                        routing_key=binding.get('routing_key', ''),
                    )

    def bind(self, username):
        """
        Declare a dynamic queue to consume user messages
        and set active user
        """
        self.user = username
        self.queue, mc, cc = self.ch.queue.declare(exclusive=True)
        self.ch.queue.bind(self.queue, self.user_subscribe_exchange(username))

    def create_users(self, usernames):
        """
            Batch create user exchanges
        """
        for username in usernames:
            self.create_user(username)

    def create_user(self, username, create_exchanges=True):
        """
            Creates user exchanges and internal binding
        """
        if create_exchanges:
            self.ch.exchange.declare(
                exchange=self.user_publish_exchange(username),
                type=self.exchange_specs_by_name['user_publish']['type'],
                durable=True,
                auto_delete=False
            )

            self.ch.exchange.declare(
                exchange=self.user_subscribe_exchange(username),
                type=self.exchange_specs_by_name['user_subscribe']['type'],
                durable=True,
                auto_delete=False
            )

        self.ch.exchange.bind(
            exchange=self.user_subscribe_exchange(username),
            source=self.user_publish_exchange(username),
            routing_key='internal',
        )

    def delete_user(self, username):
        self.ch.exchange.delete(self.user_publish_exchange(username))
        self.ch.exchange.delete(self.user_subscribe_exchange(username))

    def user_publish_exchange(self, username):
        """
            Returns name of exchange used to send messages to rabbit
        """
        return '{}.publish'.format(username)

    def user_subscribe_exchange(self, username):
        """
            Returns name of exchange used to broadcast messages for this user to all
            the consumers identified with this username
        """
        return '{}.subscribe'.format(username)

    def send(self, exchange, message, routing_key=''):
        body = message if isinstance(message, basestring) else json.dumps(message)
        message = Message(body)
        self.ch.publish(message, exchange, routing_key=routing_key)

    def send_internal(self, message):
        self.send(self.user_publish_exchange(self.user), message, routing_key='internal')

    def get_all(self, queue=None, retry=False):
        queue_name = self.queue if queue is None else queue
        messages = []
        message_obj = True
        tries = 1 if not retry else -1
        while not(tries == 0 or messages != []):
            while message_obj is not None:
                message_obj = self.get(queue_name)
                if message_obj is not None:
                    tries = 1
                    try:
                        message = (json.loads(str(message_obj.body)), message_obj)
                    except ValueError:
                        message = (message_obj.body, message_obj)
                    messages.append(message)
            tries -= 1
            message_obj = True
        return messages

    def get(self, queue_name):
        return self.ch.basic.get(queue_name)
コード例 #41
0
class SynchronousAmqpClient(object):
    """Synchronous (blocking) AMQP client abstraction that exposes AMQP
  functionality presently needed by nta.utils and products. New AMQP
  functionality will be exposed as the need arises.

  This class provides a consistent AMQP client API to the rest of the products
  regardless of the underlying implementation. This helps avoid/minimize changes
  to the higher-level code when we need to swap out the underlying client
  implementation.

  This class is NOT the place for higher-level constructs: see
  message_bus_connector module for an example of higher-level functionality
  built on top of this class.

  NOTE: this implementation is completely synchronous and MUST NOT expose
  callbacks (callbaks lead to complexities, such as an opportunity for
  unintended/unsupported recursion)

  NOTE: The `no*` parameters, such as `noLocal` and `noAck`, are artificats
  of the AMQP protocol specification. The author of SynchronousAmqpClient chose
  to preserve those semantics to facilitate better correlation with AMQP
  documentation.
  """
    # Correlations between names of BasicProperties attributes and Haigha's
    # message property names.
    #
    # The table consists of the tollowing columns
    #     BasicProperty attribute name
    #     Corresponding Haigha property name
    #     Value conversion function from BasicProperty to Haigha
    #     Value conversion function from Haigha to BasicProperty
    #
    _asIs = lambda x: x
    _PROPERTY_CORRELATIONS = (
        ("contentType", "content_type", _asIs, _asIs),
        ("contentEncoding", "content_encoding", _asIs, _asIs),
        ("headers", "application_headers", _asIs, _asIs),
        ("deliveryMode", "delivery_mode", _asIs, _asIs),
        ("priority", "priority", _asIs, _asIs),
        ("correlationId", "correlation_id", _asIs, _asIs),
        ("replyTo", "reply_to", _asIs, _asIs),
        ("expiration", "expiration", _asIs, _asIs),
        ("messageId", "message_id", _asIs, _asIs),
        ("timestamp", "timestamp", datetime.utcfromtimestamp,
         epochFromNaiveUTCDatetime),
        ("messageType", "type", _asIs, _asIs),
        ("userId", "user_id", _asIs, _asIs),
        ("appId", "app_id", _asIs, _asIs),
        ("clusterId", "cluster_id", _asIs, _asIs),
    )

    # haigha returns body as bytearray, but our current users of the interface
    # assume they are getting str or bytes
    _decodeMessageBody = str

    # NOTE: RabbitMQ release 3.5.5, changed the server's default heartbeat timeout
    # from 580 to 60, causing frequent dropped connections on our blocking
    # transport. So, we restore the longer timeout by passing a bigger value
    # to the broker during connection tuning.
    _DEFAULT_HEARTBEAT_TIMEOUT_SEC = 600

    def __init__(self, connectionParams=None, channelConfigCb=None):
        """
    NOTE: Connection establishment may be performed in the scope of the
    constructor or on demand, depending on the underlying implementation

    :param nta.utils.amqp.connection.ConnectionParams connectionParams:
      parameters for connecting to AMQP broker;
      [default=default params for RabbitMQ broker on localhost]
    :param channelConfigCb: An optional callback function that will be
      called whenever a new AMQP Channel is being brought up
    :type channelConfigCb: None or callable with the signature
      channelConfigCb(SynchronousAmqpClient)
    """
        self._channelConfigCb = channelConfigCb

        # Holds _ChannelContext when channel is created; we create the channel on
        # demand. The implementation accesses this member via the
        # `_liveChannelContext` property getter when it's desirable to bring up the
        # channel on-on demand. When it's undesirable to bring up the channel, the
        # implementation interacts directly with this member, which will be None
        # when we don't have a channel.
        self._channelContextInstance = None

        # Set to True when user calls close, so we know to not raise an exception
        # from our _on*Closed callback methods
        self._userInitiatedClosing = False

        # Instantiate underlying connection object
        params = (connectionParams if connectionParams is not None else
                  amqp_connection.ConnectionParams())

        # NOTE: we could get a `close_cb` call from RabbitConnection constructor, so
        # prepare for it by initializing `self._connection`
        self._connection = None
        self._connection = RabbitConnection(
            transport="socket",
            sock_opts={(socket.IPPROTO_TCP, socket.TCP_NODELAY): 1},
            synchronous=True,
            close_cb=self._onConnectionClosed,
            user=params.credentials.username,
            password=params.credentials.password,
            vhost=params.vhost,
            host=params.host,
            port=params.port,
            heartbeat=self._DEFAULT_HEARTBEAT_TIMEOUT_SEC,
            logger=g_log)

    def __repr__(self):
        # NOTE: we don't use the _liveChannelContext property getter in order to
        # avoid creation of channel here
        return "%s(channelContext=%r)" % (self.__class__.__name__,
                                          self._channelContextInstance)

    @property
    def _liveChannelContext(self):
        """NOTE: Creates channel on demand"""
        if self._channelContextInstance is None:
            self._channelContextInstance = _ChannelContext(
                self._connection.channel(synchronous=True))
            try:
                self._channelContextInstance.channel.add_close_listener(
                    self._onChannelClosed)

                self._channelContextInstance.channel.basic.set_return_listener(
                    self._onMessageReturn)

                if self._channelConfigCb is not None:
                    self._channelConfigCb(self)
            except Exception:  # pylint: disable=W0703
                g_log.exception("Channel configuration failed")
                try:
                    # Preserve the original exception
                    raise
                finally:
                    # Close channel and reset channel context
                    try:
                        if self._channelContextInstance is not None:
                            self._channelContextInstance.channel.close(
                                disconnect=True)
                    except Exception:  # pylint: disable=W0703
                        # Suppress the secondary exception from cleanup
                        g_log.exception(
                            "Channel closing Failed following configuration failure"
                        )
                    finally:
                        self._channelContextInstance.reset()
                        self._channelContextInstance = None

        return self._channelContextInstance

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def isOpen(self):
        return self._connection is not None and not self._connection.closed

    def close(self):
        """Gracefully close client"""
        self._userInitiatedClosing = True
        try:
            # NOTE: we check _channelContextInstance directly to avoid creating a
            # channel if one doesn't exist
            if self._channelContextInstance is not None:
                channelContext = self._channelContextInstance
                try:
                    channelContext.channel.close()
                except Exception:  # pylint: disable=W0703
                    g_log.exception("Channel close failed")

            if self._connection is not None:
                try:
                    self._connection.close(disconnect=True)
                except Exception:  # pylint: disable=W0703
                    g_log.exception("Connection close failed")
        finally:
            self._connection = None
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None

    def enablePublisherAcks(self):
        """Enable RabbitMQ publisher acknowledgments

    :raises nta.utils.amqp.exceptions.UnroutableError: raised when messages
      that were sent in non-publisher-acknowledgments mode are returned by
      the time the Confirm.Select-Ok is received
    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        channelContext = self._liveChannelContext

        if channelContext.pubacksSelected:
            g_log.warning("enablePublisherAcks: already enabled")
        else:
            channelContext.channel.confirm.select(nowait=False)
            channelContext.pubacksSelected = True

            # NOTE: Unroutable messages returned after this will be in the context of
            # publisher acknowledgments
            self._raiseAndClearIfReturnedMessages()

    def publish(self, message, exchange, routingKey, mandatory=False):
        """ Publish a message

    :param nta.utils.amqp.messages.Message message:
    :param str exchange: destination exchange name; "" for default exchange
    :param str routingKey: Message routing key
    :param bool mandatory: This flag tells the server how to react if the
      message cannot be routed to a queue. If this flag is True, the server will
      return an unroutable message with a Return method. If this flag is False
      the server silently drops the message.

    :raises nta.utils.amqp.exceptions.UnroutableError: when in
      non-publisher-acknowledgments mode, raised before attempting to publish
      given message if unroutable messages had been returned. In
      publisher-acknowledgments mode, raised if the given
      message is returned as unroutable.
    :raises nta.utils.amqp.exceptions.NackError: when the given message is
      NACKed by broker while channel is in RabbitMQ publisher-acknowledgments
      mode
    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        message = HaighaMessage(body=message.body,
                                **self._makeHaighaPropertiesDict(
                                    message.properties))

        channelContext = self._liveChannelContext

        if channelContext.pubacksSelected:
            # In publisher-acknowledgments mode
            assert not channelContext.returnedMessages, (
                len(channelContext.returnedMessages),
                channelContext.returnedMessages)

            pubackState = _PubackState()
            channelContext.channel.basic.set_ack_listener(
                pubackState.handleAck)
            channelContext.channel.basic.set_nack_listener(
                pubackState.handleNack)

            deliveryTag = channelContext.channel.basic.publish(
                message,
                exchange=exchange,
                routing_key=routingKey,
                mandatory=mandatory)

            # Wait for ACK or NACK
            while not pubackState.ready:
                self._connection.read_frames()

            try:
                ((how, responseTag), ) = pubackState.values
            except ValueError:
                g_log.exception("Error unpacking values=%r",
                                pubackState.values)
                raise

            assert responseTag == deliveryTag, ((how, responseTag),
                                                deliveryTag)

            if how == _PubackState.NACK:
                # Raise NackError with returned message
                returnedMessages = channelContext.returnedMessages
                channelContext.returnedMessages = []

                raise amqp_exceptions.NackError(returnedMessages)

            # It was Acked
            assert how == _PubackState.ACK, how

            # Raise if this message was returned as unroutable
            self._raiseAndClearIfReturnedMessages()

        else:
            # Not in publisher-acknowledgments mode

            # Raise if some prior messages were returned as unroutable
            self._raiseAndClearIfReturnedMessages()

            channelContext.channel.basic.publish(message,
                                                 exchange=exchange,
                                                 routing_key=routingKey,
                                                 mandatory=mandatory)

    def requestQoS(self,
                   prefetchSize=0,
                   prefetchCount=0,
                   entireConnection=False):
        """This method requests a specific quality of service. The QoS can be
    specified for the current channel or for all channels on the connection. The
    particular properties and semantics of a qos method always depend on the
    content class semantics

    :param int prefetchSize: The client can request that messages be sent in
      advance so that when the client finishes processing a message, the
      following message is already held locally, rather than needing to be sent
      down the channel. Prefetching gives a performance improvement. This field
      specifies the prefetch window size in octets. The server will send a
      message in advance if it is equal to or smaller in size than the available
      prefetch size (and also falls into other prefetch limits). May be set to
      zero, meaning "no specific limit", although other prefetch limits may
      still apply. The prefetchsize is ignored if the no-ack option is set.
    :param int prefetchCount: Specifies a prefetch window in terms of whole
      messages. This field may be used in combination with the prefetch-size
      field; a message will only be sent in advance if both prefetch windows
      (and those at the channel and connection level) allow it. The
      prefetch-count is ignored if the no-ack option is set.
    :param bool entireConnection: By default the QoS settings apply to the
      current channel only. If this field is set, they are applied to the entire
      connection.

    :raises AmqpChannelError:
    """
        self._liveChannelContext.channel.basic.qos(
            prefetch_size=prefetchSize,
            prefetch_count=prefetchCount,
            is_global=entireConnection)

    def createConsumer(self,
                       queue,
                       noLocal=False,
                       noAck=False,
                       exclusive=False):
        """This method asks the server to start a "consumer", which is a transient
    request for messages from a specific queue. Consumers last as long as the
    channel they were declared on, or until the client or broker cancels them.
    See `Consumer.cancel()`

    Use `getNextEvent()` to retrieve consumed messages and other events.

    :param str queue: name of the queue to consume from
    :param bool noLocal: If true, the server will not send messages to the
      connection that published them.
    :param bool noAck: if true, the broker will not expect messages to be ACKed
    :param bool exclusive: Request exclusive consumer access, meaning only this
      consumer can access the queue

    :returns: consumer context
    :rtype: nta.utils.amqp.consumer.Consumer

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    :raises nta.utils.amqp.exceptions.AmqpConnectionError:
    """
        consumerTag = self._makeConsumerTag()

        channelContext = self._liveChannelContext

        channelContext.channel.basic.consume(
            queue,
            consumer=self._onMessageDelivery,
            consumer_tag=consumerTag,
            no_local=noLocal,
            no_ack=noAck,
            exclusive=exclusive,
            cancel_cb=self._onConsumerCancelled,
            nowait=False)

        channelContext.consumerSet.add(consumerTag)

        consumer = amqp_consumer.Consumer(
            tag=consumerTag,
            queue=queue,
            cancelImpl=channelContext.cancelConsumer)

        g_log.info(
            "Created consumer=%r; queue=%r, noLocal=%r, noAck=%r, exclusive=%r",
            consumer, queue, noLocal, noAck, exclusive)

        return consumer

    def hasEvent(self):
        """Check if there are events ready for consumption. See `getNextEvent()`.

    :returns: True if there is at least one event ready for consumption, in
      which case `getNextEvent()` may be called once without blocking.
    :rtype: bool
    """
        channelContext = self._channelContextInstance
        return bool(channelContext is not None
                    and channelContext.pendingEvents)

    def getNextEvent(self):
        """Get next event, blocking if there isn't one yet. See `hasEvent()`. You
    MUST have an active consumer (`createConsumer`) or other event source before
    calling this method.

    An event may be an object of one of the following classes:

      nta.utils.amqp.messages.ConsumerMessage
      nta.utils.amqp.consumer.ConsumerCancellation

    :returns: the next event when it becomes available

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        # We expect the context to be set up already
        channelContext = self._channelContextInstance

        while not channelContext.pendingEvents:
            self._connection.read_frames()

        return channelContext.pendingEvents.popleft()

    def readEvents(self):
        """Generator that yields results of `getNextEvent()`"""
        while True:
            yield self.getNextEvent()

    def getOneMessage(self, queue, noAck=False):
        """This is the polling, less-performant method of getting a message. This
    method provides a direct access to the messages in a queue using a
    synchronous dialogue that is designed for specific types of application
    where synchronous functionality is more important than performance.

    :param str queue: name of the queue to get a message from
    :param bool noAck: if true, the broker will not be expecting an Ack

    :returns: A PolledMessage object if there was a message in queue; None if
      there was no message in queue.
    :rtype: PolledMessage or None

    :raises AmqpChannelError:
    """
        channelContext = self._liveChannelContext

        consumer = _CallbackSink()

        channelContext.channel.basic.get(queue,
                                         consumer=consumer,
                                         no_ack=noAck)
        while not consumer.ready:
            self._connection.read_frames()

        try:
            ((message, ), ) = consumer.values
        except ValueError:
            g_log.exception("Error unpacking values=%r", consumer.values)
            raise

        if message is not None:
            ackImpl = channelContext.ack if not noAck else None
            nackImpl = channelContext.nack if not noAck else None
            message = self._makePolledMessage(message, ackImpl, nackImpl)

        return message

    @classmethod
    def _makePolledMessage(cls, haighaMessage, ackImpl, nackImpl):
        """Make PolledMessage from haigha message retrieved via Basic.Get

    :param haigha.message.Message haighaMessage: haigha message retrieved via
      Basic.Get
    :param ackImpl: callable for acking the message that has the following
      signature: ackImpl(deliveryTag, multiple=False); or None
    :param nackImpl: callable for nacking the message that has the following
      signature: nackImpl(deliveryTag, requeue); or None

    :rtype: nta.utils.amqp.messages.PolledMessage
    """
        info = haighaMessage.delivery_info

        methodInfo = amqp_messages.MessageGetInfo(
            deliveryTag=info["delivery_tag"],
            redelivered=bool(info["redelivered"]),
            exchange=info["exchange"],
            routingKey=info["routing_key"],
            messageCount=info["message_count"])

        return amqp_messages.PolledMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo,
            ackImpl=ackImpl,
            nackImpl=nackImpl)

    def recover(self, requeue=False):
        """This method asks the server to redeliver all unacknowledged messages on a
    specified channel. Zero or more messages may be redelivered.

    NOTE: RabbitMQ does not currently support recovering with requeue=False

    :param bool requeue: If false, the message will be redelivered to the
      original recipient. If true, the server will attempt to requeue the
      message, potentially then delivering it to an alternative subscriber.
    """
        self._liveChannelContext.channel.basic.recover(requeue=requeue)

    def ackAll(self):
        """Acknowledge all unacknowledged messages on current channel instance.

    Acknowledgemets related to specific messages are performed via the message's
    own `ack()` method.

    NOTE: messages received prior to the AmqpChannelError exception cannot be
    acknowledged since that exception occurs after the AMQP channel is closed
    """
        self._channelContextInstance.ack(deliveryTag=0, multiple=True)

    def nackAll(self, requeue=False):
        """Reject all outstanding (unacknowledged) messages on current channel
    instance.

    Rejections related to specific messages are performed via the message's
    own `nack()` method.

    NOTE: has no impact on messages received prior to the AmqpChannelError
    exception since AmqpChannelError is raised after the AMQP channel is closed

    :param bool requeue: If requeue is true, the server will attempt to requeue
      the messages. If requeue is false or the requeue attempt fails the
      messages are discarded or dead-lettered
    """
        self._channelContextInstance.nack(deliveryTag=0,
                                          multiple=True,
                                          requeue=requeue)

    def declareExchange(self,
                        exchange,
                        exchangeType,
                        passive=False,
                        durable=False,
                        autoDelete=False,
                        arguments=None):
        """Declare an exchange

    :param str exchange: name of the exchange
    :param str exchangeType: type of the exchange
    :param bool passive: If True, the server will reply with Declare-Ok if the
      exchange already exists with the same name, and raise an error if not. The
      client can use this to check whether an exchange exists without modifying
      the server state. When set, all other method fields except name are
      ignored. Arguments are compared for semantic equivalence.
    :param bool durable: If True when creating a new exchange, the exchange will
      be marked as durable. Durable exchanges remain active when a server
      restarts. Non-durable exchanges (transient exchanges) are purged if/when a
      server restarts.
    :param bool autoDelete: If true, the exchange is deleted when all queues
      have finished using it (RabbitMQ-specific).
    :param dict arguments: custom key/value pairs for the exchange

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.exchange.declare(
            exchange,
            exchangeType,
            passive=passive,
            durable=durable,
            auto_delete=autoDelete,
            arguments=arguments or dict(),
            nowait=False)

    def deleteExchange(self, exchange, ifUnused=False):
        """Delete an exchange

    :param str exchange: exchange to be deleted
    :param bool ifUnused: If True, the server will only delete the exchange if
      it has no queue bindings. If the exchange has queue bindings the server
      does not delete it but raises a channel exception instead.

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.exchange.delete(exchange,
                                                         if_unused=ifUnused,
                                                         nowait=False)

    def declareQueue(self,
                     queue,
                     passive=False,
                     durable=False,
                     exclusive=False,
                     autoDelete=False,
                     arguments=None):
        """Declare a queue

    :param str queue: name of queue
    :param bool passive: If True, the server will reply with Declare-Ok if the
      queue already exists with the same name, and raise an error if not. The
      client can use this to check whether a queue exists without modifying the
      server state. When set, all other method fields except name are ignored.
      Arguments are compared for semantic equivalence.
    :param bool durable: If true when creating a new queue, the queue will be
      marked as durable. Durable queues remain active when a server restarts.
      Non-durable queues (transient queues) are purged if/when a server
      restarts. Note that durable queues do not necessarily hold persistent
      messages, although it does not make sense to send persistent messages to a
      transient queue.
    :param bool exclusive: Exclusive queues may only be accessed by the current
      connection, and are deleted when that connection closes. Passive
      declaration of an exclusive queue by other connections are not allowed.
    :param bool autoDelete: If true, the queue is deleted when all consumers
      have finished using it. The last consumer can be cancelled either
      explicitly or because its channel is closed. If there was no consumer ever
      on the queue, it won't be deleted. Applications can explicitly delete
      auto-delete queues using the Delete method as normal. (RabbitMQ-specific)
    :param dict arguments: A set of key/value pairs for the declaration. The
      syntax and semantics of these arguments depends on the server
      implementation.

    :rtype: nta.utils.amqp.queue.QueueDeclarationResult

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        queue, messageCount, consumerCount = (
            self._liveChannelContext.channel.queue.declare(
                queue,
                passive=passive,
                durable=durable,
                exclusive=exclusive,
                auto_delete=autoDelete,
                arguments=arguments or dict(),
                nowait=False))

        return amqp_queue.QueueDeclarationResult(queue, messageCount,
                                                 consumerCount)

    def deleteQueue(self, queue, ifUnused=False, ifEmpty=False):
        """Delete a queue. When a queue is deleted any pending messages are sent to
    a dead-letter queue if this is defined in the server configuration, and all
    consumers on the queue are cancelled

    :param str queue: name of the queue to delete
    :param bool ifUnused: If true, the server will only delete the queue if it
      has no consumers. If the queue has consumers the server does does not
      delete it but raises a channel exception instead.
    :param bool ifEmpty: If true, the server will only delete the queue if it
      has no messages

    :returns: number of messages deleted
    :rtype: int

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        return self._liveChannelContext.channel.queue.delete(
            queue, if_unused=ifUnused, if_empty=ifEmpty, nowait=False)

    def purgeQueue(self, queue):
        """Remove all messages from a queue which are not awaiting acknowledgment.

    :param str queue: name of the queue to purge

    :returns: number of messages purged
    :rtype: int

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        return self._liveChannelContext.channel.queue.purge(queue,
                                                            nowait=False)

    def bindQueue(self, queue, exchange, routingKey, arguments=None):
        """Bind a queue to an exchange

    :param str queue: name of the queue to bind
    :param str exchange: name of the exchange to bind to
    :param str routingKey: Specifies the routing key for the binding. The
      routing key is used for routing messages depending on the exchange
      configuration. Not all exchanges use a routing key refer to the
      specific exchange documentation. If the queue name is empty, the server
      uses the last queue declared on the channel. If the routing key is also
      empty, the server uses this queue name for the routing key as well. If the
      queue name is provided but the routing key is empty, the server does the
      binding with that empty routing key. The meaning of empty routing keys
      depends on the exchange implementation.
    :param dict arguments: A set of key/value pairs for the binding. The syntax
      and semantics of these arguments depends on the exchange class and server
      implemenetation.

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.queue.bind(queue=queue,
                                                    exchange=exchange,
                                                    routing_key=routingKey,
                                                    arguments=arguments
                                                    or dict(),
                                                    nowait=False)

    def unbindQueue(self, queue, exchange, routingKey, arguments=None):
        """Unbind a queue fro an exchange

    :param str queue: name of the queue to unbind
    :param str exchange: name of the exchange to unbind from
    :param str routingKey: the routing key of the binding to unbind
    :param dict arguments: Specifies the arguments of the binding to unbind

    :raises nta.utils.amqp.exceptions.AmqpChannelError:
    """
        self._liveChannelContext.channel.queue.unbind(queue=queue,
                                                      exchange=exchange,
                                                      routing_key=routingKey,
                                                      arguments=arguments
                                                      or dict())

    def _raiseAndClearIfReturnedMessages(self):
        """If returned messages are present, raise UnroutableError and clear
    returned messages holding buffer

    :raises nta.utils.amqp.exceptions.UnroutableError: if returned messages
      are present
    """
        channelContext = self._channelContextInstance

        if channelContext and channelContext.returnedMessages:
            messages = channelContext.returnedMessages
            channelContext.returnedMessages = []
            raise amqp_exceptions.UnroutableError(messages)

    @classmethod
    def _makeHaighaPropertiesDict(cls, BasicProperties):
        """Marshal BasicProperties into the haigha properties dict

    :param nta.utils.amqp.messages.BasicProperties BasicProperties:

    :returns: dict of Properties expected by Haigha's publish method
    :rtype: dict
    """
        props = dict()

        for attrName, propName, clientToHaigha, _ in cls._PROPERTY_CORRELATIONS:
            value = getattr(BasicProperties, attrName)
            # Add only those properties that have concrete values
            if value is not None:
                props[propName] = clientToHaigha(value)

        return props

    @classmethod
    def _makeBasicProperties(cls, haighaProperties):
        attributes = dict()

        for attrName, propName, _, haighaToClient in cls._PROPERTY_CORRELATIONS:
            value = haighaProperties.get(propName)

            if value is not None:
                value = haighaToClient(value)

            attributes[attrName] = value

        return amqp_messages.BasicProperties(**attributes)

    def _makeConsumerTag(self):
        channelContext = self._liveChannelContext

        tag = "channel-%d-%d" % (channelContext.channel.channel_id,
                                 channelContext.nextConsumerTag)
        channelContext.nextConsumerTag += 1
        return tag

    def _onMessageDelivery(self, message):
        """Handle consumer message from Basic.Deliver

    :param haigha.message.Message message:
    """
        channelContext = self._channelContextInstance

        g_log.debug("Consumer message received: %.255s", message)
        channelContext.pendingEvents.append(
            self._makeConsumerMessage(message, channelContext.ack,
                                      channelContext.nack))

    @classmethod
    def _makeConsumerMessage(cls, haighaMessage, ackImpl, nackImpl):
        """Make ConsumerMessage from haigha message received via Basic.Deliver

    :param haigha.message.Message haighaMessage: haigha message received via
      Basic.Deliver
    :param ackImpl: callable for acking the message that has the following
      signature: ackImpl(deliveryTag, multiple=False); or None
    :param nackImpl: callable for nacking the message that has the following
      signature: nackImpl(deliveryTag, requeue); or None

    :rtype: ConsumerMessage
    """
        info = haighaMessage.delivery_info

        methodInfo = amqp_messages.MessageDeliveryInfo(
            consumerTag=info["consumer_tag"],
            deliveryTag=info["delivery_tag"],
            redelivered=bool(info["redelivered"]),
            exchange=info["exchange"],
            routingKey=info["routing_key"])

        return amqp_messages.ConsumerMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo,
            ackImpl=ackImpl,
            nackImpl=nackImpl)

    def _onConsumerCancelled(self, consumerTag):
        """Handle notification of Basic.Cancel from broker

    :param str consumerTag: tag of consumer cancelled by broker
    """
        channelContext = self._channelContextInstance

        channelContext.pendingEvents.append(
            amqp_consumer.ConsumerCancellation(consumerTag))

        channelContext.consumerSet.discard(consumerTag)

    def _onMessageReturn(self, message):
        """Handle unroutable message returned by broker

    NOTE: this may happen regardless of RabbitMQ-specific puback mode; however,
    if it's going to happen in puback mode, RabbitMQ guarantees that it will
    take palce *before* Basic.Ack

    :param haigha.message.Message message:
    """
        g_log.warning("Message returned: %.255s", message)

        self._channelContextInstance.returnedMessages.append(
            self._makeReturnedMessage(message))

    @classmethod
    def _makeReturnedMessage(cls, haighaMessage):
        """
    :param haigha.message.Message haighaMessage: haigha message returned via
      Basic.Return

    :rtype: nta.utils.amqp.messages.ReturnedMessage
    """
        info = haighaMessage.return_info

        methodInfo = amqp_messages.MessageReturnInfo(
            replyCode=info["reply_code"],
            replyText=info["reply_text"],
            exchange=info["exchange"],
            routingKey=info["routing_key"])

        return amqp_messages.ReturnedMessage(
            body=cls._decodeMessageBody(haighaMessage.body),
            properties=cls._makeBasicProperties(haighaMessage.properties),
            methodInfo=methodInfo)

    @staticmethod
    def _amqpErrorArgsFromCloseInfo(closeInfo):
        """
    :param dict closeInfo: channel or connection close_info from Haigha

    :returns: a dict with property names compatible with _AmqpErrorBase
      constructor args
    """
        return dict(code=closeInfo["reply_code"],
                    text=closeInfo["reply_text"],
                    classId=closeInfo["class_id"],
                    methodId=closeInfo["method_id"])

    def _onConnectionClosed(self):
        try:
            if self._connection is None:
                # Failure during connection setup
                raise amqp_exceptions.AmqpConnectionError(
                    code=0,
                    text="connection setup failed",
                    classId=0,
                    methodId=0)

            closeInfo = self._connection.close_info

            if self._userInitiatedClosing:
                if closeInfo["reply_code"] != 0:
                    raise amqp_exceptions.AmqpConnectionError(
                        **self._amqpErrorArgsFromCloseInfo(closeInfo))
            else:
                raise amqp_exceptions.AmqpConnectionError(
                    **self._amqpErrorArgsFromCloseInfo(closeInfo))
        finally:
            self._connection = None
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None

    def _onChannelClosed(self, channel):
        try:
            closeInfo = channel.close_info

            if self._userInitiatedClosing:
                if closeInfo["reply_code"] != 0:
                    raise amqp_exceptions.AmqpChannelError(
                        **self._amqpErrorArgsFromCloseInfo(closeInfo))
            else:
                raise amqp_exceptions.AmqpChannelError(
                    **self._amqpErrorArgsFromCloseInfo(closeInfo))
        finally:
            if self._channelContextInstance is not None:
                self._channelContextInstance.reset()
                self._channelContextInstance = None
コード例 #42
0
import json
import os
import time

from haigha.connections.rabbit_connection import RabbitConnection
from haigha.message import Message

connection = RabbitConnection(user=os.getenv('RABBITMQ_USER'),
                              password=os.getenv('RABBITMQ_PASS'),
                              vhost='/',
                              host=os.getenv('RABBITMQ_HOSTS',
                                             'localhost').split(',')[0],
                              heartbeat=None,
                              debug=True)

ch = connection.channel()
ch.exchange.declare('cronq', 'direct')
ch.queue.declare('cronq_jobs', auto_delete=False)
ch.queue.declare('cronq_results', auto_delete=False)
ch.queue.bind('cronq_jobs', 'cronq', 'cronq_jobs')
ch.queue.bind('cronq_results', 'cronq', 'cronq_results')

while True:
    print 'publish'
    cmd = {
        "cmd": "sleep 1",
        "job_id": 1024,
        "name": "[TEST] A test job",
        "run_id": "1234"
    }
    ch.basic.publish(Message(json.dumps(cmd),
コード例 #43
0
ファイル: queue_connection.py プロジェクト: weburnit/cronq
class QueueConnection(object):
    """A wrapper around an AMQP connection for ease of publishing

    Simple instantiation:

        RABBITMQ_URL = os.getenv('RABBITMQ_URL', 'amqp://guest@localhost')
        queueconnection = QueueConnection(RABBITMQ_URL)

    Publishing requires knowing the exchange, routing_key, (headers) and
    the string body:

        # We don't really use headers
        # look up AMQP stuff if you are interested
        queueconnection.publish(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body='String Body'
        )

    Usually we want to publish JSON so there is a method that will serialize
    a dict for you:

        # We don't really use headers
        # look up AMQP stuff if you are interested
        queueconnection.publish_json(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body={'key': 'value'}
        )

    All of these are asynchronous publishes to the server, if you want to make
    sure that these at least make it to the server you can turn on publisher
    confirmations. Sync calls take longer so they aren't on by default. Turning
    them on is done by passing `confirm=True` to the constructor.

        RABBITMQ_URL = os.getenv('RABBITMQ_URL', 'amqp://guest@localhost')
        queueconnection = QueueConnection(RABBITMQ_URL, confirm=True)

    Now publishes will return a bool of whether the publish succeeded.

        # We don't really use headers
        # look up AMQP stuff if you are interested
        succeeded = queueconnection.publish(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body='String Body'
        )

    Without `confirm=True` the return value of publish will only indicate if
    the message was written to a connection successfully.

    """
    def __init__(self, url=None, confirm=False, **kwargs):
        if url is None:
            url = Config.RABBITMQ_URL
        hosts, user, password, vhost, port, heartbeat = parse_url(url)

        if heartbeat is None:
            heartbeat = kwargs.get('heartbeat', None)

        self._connection_hosts = hosts
        self._connection_user = user
        self._connection_password = password
        self._connection_path = vhost
        self._connection_port = port
        self._connection_heartbeat = heartbeat
        self._connection_name = self._generate_connection_name()

        self._connection_params = urlparse.urlparse(url)
        self._connect_attempt_delay = 0.1

        self._get_next_host = create_host_factory(self._connection_hosts)

        self._confirm = confirm
        self._logger = logger

        self._create_connection()

        self._acked = False
        self._last_confirmed_message = None

    def _create_connection(self):
        "Tries to create a connection, returns True on success"
        self._connection = None
        self._last_confirmed_message = None
        host = self._get_next_host()
        self._logger.debug('Trying to connect to {}'.format(host))
        try:
            self._connection = RabbitConnection(
                host=host,
                port=self._connection_port,
                user=self._connection_user,
                password=self._connection_password,
                vhost=self._connection_path,
                close_cb=self._close_cb,
                heartbeat=self._connection_heartbeat,
                client_properties={
                    'connection_name': self._connection_name,
                },
            )
        except socket.error as exc:
            self._logger.error('Error connecting to rabbitmq {}'.format(exc))
            return False
        self._channel = self._connection.channel()
        if self._confirm:
            self._channel.confirm.select(nowait=False)
            self._channel.basic.set_ack_listener(self._ack)
        self._logger.debug('Connected to {}'.format(host))
        return True

    def _generate_connection_name(self):
        random_generator = random.SystemRandom()
        random_string = ''.join([
            random_generator.choice(string.ascii_lowercase) for i in xrange(10)
        ])
        return '{0}-{1}-{2}'.format(
            socket.gethostname(),
            os.getpid(),
            random_string,
        )

    def _try_to_connect(self, attempts=3):
        """Try to connect handling retries"""
        for _ in range(attempts):
            if self.is_connected():
                return True
            else:
                self._logger.debug("attempt to create connection")
                self._create_connection()
                time.sleep(self._connect_attempt_delay)

    def _ack(self, message_id):
        self._last_confirmed_message = message_id

    def is_connected(self):
        if self._connection is None or self._channel is None:
            return False
        return True

    def _close_cb(self):
        if self._connection is None:
            reason = 'unknown'
        else:
            reason = self._connection.close_info['reply_text']
        self._logger.info('Disconnected because: {}'.format(reason))
        self._connection = None
        self._channel = None

    def publish(self,
                exchange,
                routing_key,
                headers,
                body,
                connect_attempts=3):
        """Publish a messages to AMQP

        Returns a bool about the success of the publish. If `confirm=True` True
        means it reached the AMQP server. If `confirm=False` it means that it
        was able to be written to a connection but makes no guarantee about the
        message making it to the server.

        """
        if not self.is_connected():
            self._try_to_connect(attempts=connect_attempts)

        if self._connection is None or self._channel is None:
            self._logger.error('Tried to publish without an AMQP connection')
            return False

        msg_number = self._channel.basic.publish(Message(
            body, application_headers=headers),
                                                 exchange=exchange,
                                                 routing_key=routing_key)

        if self._confirm:
            if self.is_connected():
                self._connection.read_frames()
                return self._last_confirmed_message == msg_number
            else:
                return False

        return True

    def publish_json(self, exchange, routing_key, headers, body):
        data = json.dumps(body)
        return self.publish(exchange, routing_key, headers, data)

    def close(self):
        self._connection.close()
コード例 #44
0
ファイル: client.py プロジェクト: lipixun/pytest
 def __init__(self, host, port, vhost, user, password):
     """Create a new Server
     """
     self._conn = RabbitConnection(host = host, port = port, vhost = vhost, user = user, password = password)
     self._channel = self._conn.channel()
コード例 #45
0
ファイル: damqp.py プロジェクト: rickhanlonii/declare-amqp
def run(args):
    host = os.getenv('AMQP_HOST', 'localhost')
    user = os.getenv('AMQP_USER', 'guest')
    password = os.getenv('AMQP_PASS', 'guest')
    vhost = os.getenv('AMQP_VHOST', '/')

    connection = RabbitConnection(
      user=user, password=password,
      vhost=vhost, host=host,
      heartbeat=None, debug=True)

    config = get_config(args.config)

    ch = connection.channel()
    for exchange in config.get('exchanges'):
        print 'Declaring exchange:'
        print '\t', exchange
        try:
            ch.exchange.declare(
                exchange['name'],
                exchange['type'],
                durable=exchange['durable'],
                auto_delete=exchange['auto_delete'],
                arguments=exchange.get('arguments', {}),
            )
        except AttributeError as ae:
            print ae
            print 'Declare conflict! This must be fixed manually'
            sys.exit(1)

    for queue in config.get('queues'):
        print 'Declaring queue:'
        print '\t', queue
        try:
            ch.queue.declare(
                queue['name'],
                auto_delete=queue['auto_delete'],
                durable=queue['durable'],
                arguments=queue.get('arguments', {}),
            )
        except AttributeError as ae:
            print ae
            print 'Declare conflict! This must be fixed manually'
            sys.exit(1)
        for binding in queue['bindings']:
            print 'Binding queue:'
            print '\t', binding
            try:

                if binding.get('binding_key'):
                    ch.queue.bind(
                        queue['name'],
                        binding['exchange'],
                        binding['binding_key'],
                    )
                else:
                    ch.queue.bind(
                        queue['name'],
                        binding['exchange']
                    )
            except AttributeError:
                print 'Declare conflict! This must be fixed manually'
                sys.exit(1)
    connection.close()
コード例 #46
0
ファイル: queue_connection.py プロジェクト: seatgeek/cronq
class QueueConnection(object):

    """A wrapper around an AMQP connection for ease of publishing

    Simple instantiation:

        RABBITMQ_URL = os.getenv('RABBITMQ_URL', 'amqp://guest@localhost')
        queueconnection = QueueConnection(RABBITMQ_URL)

    Publishing requires knowing the exchange, routing_key, (headers) and
    the string body:

        # We don't really use headers
        # look up AMQP stuff if you are interested
        queueconnection.publish(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body='String Body'
        )

    Usually we want to publish JSON so there is a method that will serialize
    a dict for you:

        # We don't really use headers
        # look up AMQP stuff if you are interested
        queueconnection.publish_json(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body={'key': 'value'}
        )

    All of these are asynchronous publishes to the server, if you want to make
    sure that these at least make it to the server you can turn on publisher
    confirmations. Sync calls take longer so they aren't on by default. Turning
    them on is done by passing `confirm=True` to the constructor.

        RABBITMQ_URL = os.getenv('RABBITMQ_URL', 'amqp://guest@localhost')
        queueconnection = QueueConnection(RABBITMQ_URL, confirm=True)

    Now publishes will return a bool of whether the publish succeeded.

        # We don't really use headers
        # look up AMQP stuff if you are interested
        succeeded = queueconnection.publish(
            exchange='exchange',
            routing_key='routing_key',
            headers={},
            body='String Body'
        )

    Without `confirm=True` the return value of publish will only indicate if
    the message was written to a connection successfully.

    """

    def __init__(self, url=None, confirm=False, **kwargs):
        if url is None:
            url = Config.RABBITMQ_URL
        hosts, user, password, vhost, port, heartbeat = parse_url(url)

        if heartbeat is None:
            heartbeat = kwargs.get('heartbeat', None)

        self._connection_hosts = hosts
        self._connection_user = user
        self._connection_password = password
        self._connection_path = vhost
        self._connection_port = port
        self._connection_heartbeat = heartbeat
        self._connection_name = self._generate_connection_name()

        self._connection_params = urlparse.urlparse(url)
        self._connect_attempt_delay = 0.1

        self._get_next_host = create_host_factory(self._connection_hosts)

        self._confirm = confirm
        self._logger = logger

        self._create_connection()

        self._acked = False
        self._last_confirmed_message = None

    def _create_connection(self):
        "Tries to create a connection, returns True on success"
        self._connection = None
        self._last_confirmed_message = None
        host = self._get_next_host()
        self._logger.debug('Trying to connect to {}'.format(host))
        try:
            self._connection = RabbitConnection(
                host=host,
                port=self._connection_port,
                user=self._connection_user,
                password=self._connection_password,
                vhost=self._connection_path,
                close_cb=self._close_cb,
                heartbeat=self._connection_heartbeat,
                client_properties={
                    'connection_name': self._connection_name,
                },
            )
        except socket.error as exc:
            self._logger.error('Error connecting to rabbitmq {}'.format(exc))
            return False
        self._channel = self._connection.channel()
        if self._confirm:
            self._channel.confirm.select(nowait=False)
            self._channel.basic.set_ack_listener(self._ack)
        self._logger.debug('Connected to {}'.format(host))
        return True

    def _generate_connection_name(self):
        random_generator = random.SystemRandom()
        random_string = ''.join([random_generator.choice(string.ascii_lowercase)
                                 for i in xrange(10)])
        return '{0}-{1}-{2}'.format(
            socket.gethostname(),
            os.getpid(),
            random_string,
        )

    def _try_to_connect(self, attempts=3):
        """Try to connect handling retries"""
        for _ in range(attempts):
            if self.is_connected():
                return True
            else:
                self._logger.debug("attempt to create connection")
                self._create_connection()
                time.sleep(self._connect_attempt_delay)

    def _ack(self, message_id):
        self._last_confirmed_message = message_id

    def is_connected(self):
        if self._connection is None or self._channel is None:
            return False
        return True

    def _close_cb(self):
        if self._connection is None:
            reason = 'unknown'
        else:
            reason = self._connection.close_info['reply_text']
        self._logger.info('Disconnected because: {}'.format(reason))
        self._connection = None
        self._channel = None

    def publish(self,
                exchange,
                routing_key,
                headers,
                body,
                connect_attempts=3):
        """Publish a messages to AMQP

        Returns a bool about the success of the publish. If `confirm=True` True
        means it reached the AMQP server. If `confirm=False` it means that it
        was able to be written to a connection but makes no guarantee about the
        message making it to the server.

        """
        if not self.is_connected():
            self._try_to_connect(attempts=connect_attempts)

        if self._connection is None or self._channel is None:
            self._logger.error('Tried to publish without an AMQP connection')
            return False

        msg_number = self._channel.basic.publish(
            Message(body, application_headers=headers),
            exchange=exchange,
            routing_key=routing_key
        )

        if self._confirm:
            if self.is_connected():
                self._connection.read_frames()
                return self._last_confirmed_message == msg_number
            else:
                return False

        return True

    def publish_json(self, exchange, routing_key, headers, body):
        data = json.dumps(body)
        return self.publish(exchange, routing_key, headers, data)

    def close(self):
        self._connection.close()