使用kombu为rabbitmq实现RPC客户端,它是直接回复功能

时间:2017-05-14 07:30:49

标签: python rabbitmq rpc kombu

我正在用kombu实现一个与兔子一起使用的rpc框架 我想使用rabbitmq's direct reply-to feature,但我找不到用kombu实现它的方法。

客户端需要在生成消息之前使用'amq.rabbitmq.reply-to'队列,生产者和消费者应该使用相同的通道。 我还需要使用生产者池(或某种连接池),因为客户端是在线程环境中创建的。

到目前为止,我有这个代码,rabbitmq不会抱怨没有PRECONDITION错误的生产者(如果我删除了消费者部分,它会抱怨),但生产者不会生产任何东西!

class KombuRpcClient(RpcClientBase):
    def __init__(self, params):
        self.future = Queue.Queue()
        self.logger = logger
        if isinstance(params, RpcConnectionProperties):
            self.rpc_connection_properties = params
        else:
            self.rpc_connection_properties = RpcConnectionProperties(
                host=params.get('host'),
                port=5672,
                username=params.get('username'),
                password=params.get('password'),
                vhost=params.get('vhost') if params.has_key('vhost') else '/'
            )
        self.amqp_url = self.rpc_connection_properties.get_kombu_transport_url('pyamqp')
        self.reply_queue = KombuQueue('direct_reply', exchange=default_exchange, routing_key='amq.rabbitmq.reply-to')

    def call(self, exchange, key, msg, no_response=False, timeout=5):
        connection = Connection(self.amqp_url)
        if exchange is not None:
            key = exchange + ':' + key
        with producers_pool[connection].acquire(block=True) as producer:
            with producer.channel.Consumer(queues=[self.reply_queue], no_ack=True, callbacks=[self._on_message],
                                           accept=['ujson']) as consumer:
                producer.publish(
                    msg,
                    exchange=default_exchange,
                    routing_key=key,
                    immediate=True,
                    serializer='ujson', reply_to=self.reply_queue.routing_key)
                consumer.consume()
                pass
        res = self.future.get(block=True, timeout=timeout)
        print res

    def cast(self, exchange, key, msg):
        pass

    def _on_message(self, body, message):
        print body
        self.future.put(body)

1 个答案:

答案 0 :(得分:2)

在来自wireshark的一点帮助下,我意识到有时rabbitmq会回应那个PRECONDITION错误,但是kombu不会提出异常,我不知道为什么! 无论如何,这段代码现在正在运行:

class KombuRpcClient(RpcClientBase):
    def __init__(self, params):
        self.future = Queue.Queue()
        self.logger = logger
        if isinstance(params, RpcConnectionProperties):
            self.rpc_connection_properties = params
        else:
            self.rpc_connection_properties = RpcConnectionProperties(
                host=params.get('host'),
                port=5672,
                username=params.get('username'),
                password=params.get('password'),
                vhost=params.get('vhost') if params.has_key('vhost') else '/'
            )
        self.amqp_url = self.rpc_connection_properties.get_kombu_transport_url('pyamqp')
        self.reply_queue = KombuQueue('amq.rabbitmq.reply-to', exchange=default_exchange, routing_key='amq.rabbitmq.reply-to')

    def call(self, exchange, key, msg, no_response=False, timeout=5):
        connection = Connection(self.amqp_url)
        if exchange is not None:
            key = exchange + ':' + key

        with producers_pool[connection].acquire(block=True) as producer:
            consumer = producer.channel.Consumer(queues=[self.reply_queue], no_ack=True, auto_declare=True,
                                callbacks=[self._on_message], accept=['ujson'])
            consumer.consume(no_ack=True)
            producer.publish(msg,
                             serializer='ujson',
                             exchange=default_exchange,
                             routing_key=key,
                             reply_to='amq.rabbitmq.reply-to')
            consumer.connection.drain_events()
            res = self.future.get(block=True, timeout=timeout)
            response = Response()
            response.body = res
            return res

    def cast(self, exchange, key, msg):
        connection = Connection(self.amqp_url)
        if exchange is not None:
            key = exchange + ':' + key
        with producers_pool[connection].acquire(block=True) as producer:
            producer.publish(msg,
                             serializer='ujson',
                             exchange=default_exchange,
                             routing_key=key)

    def _on_message(self, body, message):
        print body
        self.future.put(body)
BTW:抱歉变量名称,这应该替换旧的stomp rpc客户端,所以我必须保持名称的兼容性