Exemplo n.º 1
0
    def test_get_producer(self, rabbit_config, confirms):
        amqp_uri = rabbit_config['AMQP_URI']
        producer_ids = []

        with get_producer(amqp_uri, confirms) as producer:
            producer_ids.append(id(producer))
            transport_options = producer.connection.transport_options
            assert isinstance(producer, Producer)
            assert transport_options['confirm_publish'] is confirms

        with get_producer(amqp_uri, confirms) as producer:
            producer_ids.append(id(producer))
            assert len(set(producer_ids)) == 1
Exemplo n.º 2
0
        def publish(msg, **kwargs):
            exchange = self.exchange
            serializer = self.serializer

            if exchange is None and self.queue is not None:
                exchange = self.queue.exchange

            retry = kwargs.pop('retry', self.retry)
            retry_policy = kwargs.pop('retry_policy', self.retry_policy)
            mandatory = kwargs.pop('mandatory', False)

            with get_producer(self.amqp_uri, self.use_confirms) as producer:
                headers = self.get_message_headers(worker_ctx)
                producer.publish(msg,
                                 exchange=exchange,
                                 headers=headers,
                                 serializer=serializer,
                                 retry=retry,
                                 retry_policy=retry_policy,
                                 mandatory=mandatory,
                                 **kwargs)

                if mandatory:
                    if not self.use_confirms:
                        warnings.warn(
                            "Mandatory delivery was requested, but "
                            "unroutable messages cannot be detected without "
                            "publish confirms enabled.")
                    try:
                        returned_messages = producer.channel.returned_messages
                        returned = returned_messages.get_nowait()
                    except queue.Empty:
                        pass
                    else:
                        raise UndeliverableMessage(returned)
Exemplo n.º 3
0
 def publish(msg):
     with get_producer(amqp_uri) as producer:
         producer.publish(
             msg,
             serializer="json",
             routing_key=queue.name
         )
Exemplo n.º 4
0
    def test_confirms_disabled(self, rabbit_config):
        amqp_uri = rabbit_config['AMQP_URI']

        with get_producer(amqp_uri, False) as producer:
            producer.publish(
                "msg", exchange="missing", routing_key="key"
            )
Exemplo n.º 5
0
    def _call(self, *args, **kwargs):
        _log.debug('invoking %s', self)

        worker_ctx = self.worker_ctx
        container = worker_ctx.container

        msg = {'args': args, 'kwargs': kwargs}

        # We use the `mandatory` flag in `producer.publish` below to catch rpc
        # calls to non-existent services, which would otherwise wait forever
        # for a reply that will never arrive.
        #
        # However, the basic.return ("no one is listening for topic") is sent
        # asynchronously and conditionally, so we can't wait() on the channel
        # for it (will wait forever on successful delivery).
        #
        # Instead, we make use of (the rabbitmq extension) confirm_publish
        # (https://www.rabbitmq.com/confirms.html), which _always_ sends a
        # reply down the channel. Moreover, in the case where no queues are
        # bound to the exchange (service unknown), the basic.return is sent
        # first, so by the time kombu returns (after waiting for the confim)
        # we can reliably check for returned messages.

        # Note that overriding :attr:`self.use_confirms` may disable this
        # functionality and therefore :class:`UnknownService` will never
        # be raised (and the caller will hang).

        routing_key = '{}.{}'.format(self.service_name, self.method_name)

        exchange = get_rpc_exchange(container.config)

        with get_producer(self.amqp_uri, self.use_confirms) as producer:

            headers = self.get_message_headers(worker_ctx)
            correlation_id = str(uuid.uuid4())

            reply_listener = self.reply_listener
            reply_to_routing_key = reply_listener.routing_key
            reply_event = reply_listener.get_reply_event(correlation_id)

            producer.publish(msg,
                             exchange=exchange,
                             routing_key=routing_key,
                             mandatory=True,
                             serializer=self.serializer,
                             reply_to=reply_to_routing_key,
                             headers=headers,
                             correlation_id=correlation_id,
                             retry=self.retry,
                             retry_policy=self.retry_policy)

            try:
                producer.channel.returned_messages.get_nowait()
            except queue.Empty:
                pass
            else:
                raise UnknownService(self.service_name)

        return RpcReply(reply_event)
Exemplo n.º 6
0
    def test_confirms_enabled(self, rabbit_config):
        amqp_uri = rabbit_config['AMQP_URI']

        with pytest.raises(NotFound):
            with get_producer(amqp_uri) as producer:
                producer.publish(
                    "msg", exchange="missing", routing_key="key"
                )
Exemplo n.º 7
0
    def test_pool_gives_different_producers(self, rabbit_config):
        amqp_uri = rabbit_config['AMQP_URI']
        producer_ids = []

        # get a producer
        with get_producer(amqp_uri, True) as confirmed_producer:
            producer_ids.append(id(confirmed_producer))
            assert len(set(producer_ids)) == 1

        # get a producer with the same parameters
        with get_producer(amqp_uri, True) as confirmed_producer:
            producer_ids.append(id(confirmed_producer))
            assert len(set(producer_ids)) == 1  # same producer returned

        # get a producer with different parameters
        with get_producer(amqp_uri, False) as unconfirmed_producer:
            producer_ids.append(id(unconfirmed_producer))
            assert len(set(producer_ids)) == 2  # different producer returned
Exemplo n.º 8
0
    def send_response(self, result, exc_info, **kwargs):

        error = None
        if exc_info is not None:
            error = serialize(exc_info[1])

        # disaster avoidance serialization check: `result` must be
        # serializable, otherwise the container will commit suicide assuming
        # unrecoverable errors (and the message will be requeued for another
        # victim)

        try:
            kombu.serialization.dumps(result, self.serializer)
        except Exception:
            exc_info = sys.exc_info()
            # `error` below is guaranteed to serialize to json
            error = serialize(UnserializableValueError(result))
            result = None

        exchange = get_rpc_exchange(self.config)

        retry = kwargs.pop('retry', self.retry)
        retry_policy = kwargs.pop('retry_policy', self.retry_policy)

        with get_producer(self.amqp_uri, self.use_confirms) as producer:

            routing_key = self.message.properties['reply_to']
            correlation_id = self.message.properties.get('correlation_id')

            msg = {'result': result, 'error': error}

            _log.debug('publish response %s:%s', routing_key, correlation_id)
            producer.publish(msg,
                             retry=retry,
                             retry_policy=retry_policy,
                             exchange=exchange,
                             routing_key=routing_key,
                             serializer=self.serializer,
                             correlation_id=correlation_id,
                             **kwargs)

        return result, exc_info
    def send_response(self, message, result, exc_info):

        config = self.container.config

        error = None
        if exc_info is not None:
            error = serialize(exc_info[1])

        with get_producer(config[AMQP_URI_CONFIG_KEY]) as producer:

            routing_key = message.properties.get('reply_to')

            msg = {'result': result, 'error': error}

            producer.publish(msg,
                             exchange=orders_exchange,
                             serializer=DEFAULT_SERIALIZER,
                             routing_key=routing_key)

        return result, error
Exemplo n.º 10
0
    def dispatch(service_name, event_type, event_data):
        """ Dispatch an event claiming to originate from `service_name` with
        the given `event_type` and `event_data`.
        """
        serializer = nameko_config.get(SERIALIZER_CONFIG_KEY,
                                       DEFAULT_SERIALIZER)

        exchange = get_event_exchange(service_name)

        with get_connection(amqp_uri) as connection:
            exchange.maybe_bind(connection)  # TODO: reqd? maybe_declare?
            with get_producer(amqp_uri, use_confirms) as producer:
                msg = event_data
                routing_key = event_type
                producer.publish(msg,
                                 exchange=exchange,
                                 serializer=serializer,
                                 routing_key=routing_key,
                                 retry=retry,
                                 retry_policy=retry_policy,
                                 mandatory=mandatory,
                                 **kwargs)

                if mandatory:
                    if not use_confirms:
                        warnings.warn(
                            "Mandatory delivery was requested, but "
                            "unroutable messages cannot be detected without "
                            "publish confirms enabled.")

                    try:
                        returned_messages = producer.channel.returned_messages
                        returned = returned_messages.get_nowait()
                    except queue.Empty:
                        pass
                    else:
                        raise UndeliverableMessage(returned)
Exemplo n.º 11
0
 def producer(self, get_producer):
     producer = get_producer().__enter__.return_value
     # make sure we don't raise UndeliverableMessage if mandatory is True
     producer.channel.returned_messages.get_nowait.side_effect = queue.Empty
     return producer