在前面三节中,生产者只作为消息发送方,消费者只作为消息接收方。

 

假设生产者为客户端向队列中发送消息,服务器为消费者从队列中接收消息;

现在的需求时,生产者在发消息时,要求接收到服务器的返回结果,怎么办?

如果服务器将结果放在同一个队列中,那么在同一队列中既发送又接收消息,将形成死循环。

即在同一个队列中,任何一端都不能既作为生产者又作为消息者,只能选择一方,否则就是死循环。

 

解决办法:重新声明一个队列,来存放服务器返的结果;此时服务器作为生产者,客户端作为消费者。

这个过程,也称为RPC,Remote Producre Call远程过程调用。

python rabbitmq消费数据 python rabbitmq rpc_rabbitMQ

但是,如果服务器不知道将任务结果放在哪个队列,客户端也不知道从哪个队列去取结果,怎么办?

解决办法:客户端在发送消息时,带上一个标记,如参数reply_to=任务结果的队列名称

 

假设,同一个客户端向任务器发送了三个耗时任务,要求服务器异步返回,在返回结果之前客户端可以做其它事,不需要一直等待。

解决办法:同上,除了为此客户端添加一个任务结果的队列标记外;

但是还需要分别为每个任务再加上一个新的标识符(消息区分),且实现异步返回。

即要求实现双生产、消费模式。如,客户端作为发送方发送任务,又作为接收方接收任务结果;

服务器既作为接收方接收任务,又作为发送方发送任务结果。 这就是RPC。

示例:

客户端:

import pika
import uuid


class FibonacciRpcClient(object):
    def __init__(self):
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(
            host='localhost'))
        self.channel = self.connection.channel()

        # 生成一个随机queue作为任务结果的queue
        result = self.channel.queue_declare(exclusive=True)
        self.callback_queue = result.method.queue
        # 作为接收端,准备接收任务结果
        self.channel.basic_consume(self.on_response, no_ack=True,
                                   queue=self.callback_queue)

    def on_response(self, ch, method, props, body): # 作为接收方的callback函数
        if self.corr_id == props.correlation_id:
            self.response = body

    def call(self, n):
        self.response = None
        self.corr_id = str(uuid.uuid4())  # 唯一标识符
        # 作为发送者:发送消息及唯一标识符
        self.channel.basic_publish(exchange='',
                                   routing_key='rpc_queue',
                                   properties=pika.BasicProperties(
                                       reply_to=self.callback_queue,
                                       correlation_id=self.corr_id,
                                   ),
                                   body=str(n))
        count = 0
        while self.response is None:
            # 作为接收方,检查队列中,有没有新消息,但不会阻塞即异步
            self.connection.process_data_events()
            count += 1
            print("check....", count)
        return int(self.response)

fibonacci_rpc = FibonacciRpcClient()
print(" [x] Requesting fib(30)")
response = fibonacci_rpc.call(30)
print(" [.] Got %r" % response)

服务器:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(
    host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='rpc_queue')

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

def on_request(ch, method, props, body):
    n = int(body)
    print(" [.] fib(%s)" % n)
    response = fib(n)
    # 作为发送方,发送消息
    ch.basic_publish(exchange='',
                     routing_key=props.reply_to,
                     properties=pika.BasicProperties(correlation_id= \
                                                         props.correlation_id),
                     body=str(response))
    ch.basic_ack(delivery_tag=method.delivery_tag)
# 公平分发:一次只接收prefetch_count个消息
channel.basic_qos(prefetch_count=1)
# 作为接收方,消费消息
channel.basic_consume(on_request, queue='rpc_queue')
print(" [x] Awaiting RPC requests")
channel.start_consuming()

 

参考:

celery连接rabbitMQ

https://www.jianshu.com/p/42b98f5eacb3