Ejemplo n.º 1
0
class Consumer(object):
    """ A message consumer """
    topic = None

    # Automatically decode JSON data
    jsonify = True

    def __init__(self):
        self.hub = MokshaHub()
        self.log = log
        if self.hub.amqp_broker and not self.hub.stomp_broker:
            for topic in listify(self.topic):
                log.debug('Subscribing to consumer topic %s' % topic)

                if isinstance(self.hub, AMQPLibHub):
                    # AMQPLibHub specific 
                    queue_name = str(uuid.uuid4())
                    self.hub.queue_declare(queue=queue_name, exclusive=True)
                    self.hub.exchange_bind(queue_name, binding_key=topic)
                    if self.jsonify:
                        self.hub.queue_subscribe(queue_name, self._consume_json)
                    else:
                        self.hub.queue_subscribe(queue_name, self._consume)
                else:
                    # Assume we're using Qpid then.
                    server_queue_name = 'moksha_consumer_' + self.hub.session.name
                    self.hub.queue_declare(queue=server_queue_name, exclusive=True)
                    self.hub.exchange_bind(server_queue_name, binding_key=topic)
                    local_queue_name = 'moksha_consumer_' + self.hub.session.name
                    self.hub.local_queue = self.hub.session.incoming(local_queue_name)
                    self.hub.message_subscribe(queue=server_queue_name,
                                           destination=local_queue_name)
                    self.hub.local_queue.start()
                    if self.jsonify:
                        self.hub.local_queue.listen(self._consume_json)
                    else:
                        self.hub.local_queue.listen(self._consume)

        # If the consumer specifies an 'app', then setup `self.engine` to
        # be a SQLAlchemy engine, along with a configured DBSession
        app = getattr(self, 'app', None)
        self.engine = self.DBSession = None
        if app:
            log.debug("Setting up individual engine for consumer")
            self.engine = create_app_engine(app)
            self.DBSession = sessionmaker(bind=self.engine)()

    def _consume_json(self, message):
        """ Convert our AMQP messages into a consistent dictionary format.

        This method exists because our STOMP & AMQP message brokers consume
        messages in different formats.  This causes our messaging abstraction
        to leak into the consumers themselves.

        :Note: We do not pass the message headers to the consumer (in this AMQP consumer)
        because the current AMQP.js bindings do not allow the client to change them.
        Thus, we need to throw any topic/queue details into the JSON body itself.
        """
        try:
            body = json.decode(message.body)
        except:
            log.debug("Unable to decode message body to JSON: %r" % message.body)
            body = message.body
        topic = None
        try:
            topic = message.headers[0].routing_key
        except TypeError:
            # We didn't get a JSON dictionary
            pass
        except AttributeError:
            # We didn't get headers or a routing key?
            pass

        self.consume({'body': body, 'topic': topic})

    def _consume(self, message):
        self.consume(message)

    def consume(self, message):
        raise NotImplementedError

    def send_message(self, topic, message):
        try:
            self.hub.send_message(topic, message, jsonify=self.jsonify)
        except Exception, e:
            log.error('Cannot send message: %s' % e)
Ejemplo n.º 2
0
class Consumer(object):
    """ A message consumer """
    topic = None

    # Automatically decode JSON data
    jsonify = True

    def __init__(self):
        self.hub = MokshaHub()
        self.log = log
        if self.hub.amqp_broker and not self.hub.stomp_broker:
            for topic in listify(self.topic):
                log.debug('Subscribing to consumer topic %s' % topic)

                if isinstance(self.hub, AMQPLibHub):
                    # AMQPLibHub specific
                    queue_name = str(uuid.uuid4())
                    self.hub.queue_declare(queue=queue_name, exclusive=True)
                    self.hub.exchange_bind(queue_name, binding_key=topic)
                    if self.jsonify:
                        self.hub.queue_subscribe(queue_name,
                                                 self._consume_json)
                    else:
                        self.hub.queue_subscribe(queue_name, self._consume)
                else:
                    # Assume we're using Qpid then.
                    server_queue_name = 'moksha_consumer_' + self.hub.session.name
                    self.hub.queue_declare(queue=server_queue_name,
                                           exclusive=True)
                    self.hub.exchange_bind(server_queue_name,
                                           binding_key=topic)
                    local_queue_name = 'moksha_consumer_' + self.hub.session.name
                    self.hub.local_queue = self.hub.session.incoming(
                        local_queue_name)
                    self.hub.message_subscribe(queue=server_queue_name,
                                               destination=local_queue_name)
                    self.hub.local_queue.start()
                    if self.jsonify:
                        self.hub.local_queue.listen(self._consume_json)
                    else:
                        self.hub.local_queue.listen(self._consume)

        # If the consumer specifies an 'app', then setup `self.engine` to
        # be a SQLAlchemy engine, along with a configured DBSession
        app = getattr(self, 'app', None)
        self.engine = self.DBSession = None
        if app:
            log.debug("Setting up individual engine for consumer")
            self.engine = create_app_engine(app)
            self.DBSession = sessionmaker(bind=self.engine)()

    def _consume_json(self, message):
        """ Convert our AMQP messages into a consistent dictionary format.

        This method exists because our STOMP & AMQP message brokers consume
        messages in different formats.  This causes our messaging abstraction
        to leak into the consumers themselves.

        :Note: We do not pass the message headers to the consumer (in this AMQP consumer)
        because the current AMQP.js bindings do not allow the client to change them.
        Thus, we need to throw any topic/queue details into the JSON body itself.
        """
        try:
            body = json.decode(message.body)
        except:
            log.debug("Unable to decode message body to JSON: %r" %
                      message.body)
            body = message.body
        topic = None
        try:
            topic = message.headers[0].routing_key
        except TypeError:
            # We didn't get a JSON dictionary
            pass
        except AttributeError:
            # We didn't get headers or a routing key?
            pass

        self.consume({'body': body, 'topic': topic})

    def _consume(self, message):
        self.consume(message)

    def consume(self, message):
        raise NotImplementedError

    def send_message(self, topic, message):
        try:
            self.hub.send_message(topic, message, jsonify=self.jsonify)
        except Exception, e:
            log.error('Cannot send message: %s' % e)