RabbitMQ实现的RPC
1.主要思路
1.生产者发布任务时,指定properties,告知消费者处理任务完毕之后,将结果存储到reply_to指定的Queue中,本次任务的id是correlation_id
2.消费者消费完消息,即处理完任务,将结果存储到reply_to指定的Queue中,同时指定correlation_id为从任务中获取的id
3.生产者先前已经订阅过reply_to指定的Queue,当消费者把结果回传到队列中时,生产者就可以取出结果,并对比correlation_id是否是自己想要的id以确认是否是自己发送的任务。
2.消费者代码
#_*_coding:utf-8_*_ import pika import time # 链接socket connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() # 生成rpc queue 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) # 收到消息就调用 # ch 管道内存对象地址 # method 消息发给哪个queue # props 返回给消费的返回参数 # body数据对象 def on_request(ch, method, props, body): n = int(body) print(" [.] fib(%s)" % n) # 调用斐波那契函数 传入结果 response = fib(n) ch.basic_publish(exchange='', # 生产端随机生成的queue routing_key=props.reply_to, # 获取UUID唯一 字符串数值 properties=pika.BasicProperties(correlation_id = \ props.correlation_id), # 消息返回给生产端 body=str(response)) # 确保任务完成 ch.basic_ack(delivery_tag = method.delivery_tag) # rpc_queue收到消息:调用on_request回调函数 # queue='rpc_queue'从rpc内收 channel.basic_consume(on_request, queue='rpc_queue') print(" [x] Awaiting RPC requests") channel.start_consuming()
3.生产者代码
import pika import uuid import time # 斐波那契数列 前两个数相加依次排列 class FibonacciRpcClient(object): def __init__(self): # 链接远程 self.connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) self.channel = self.connection.channel() # 生成随机queue #如果你想创建一个只有自己可见的队列,即不允许其它用户访问,RabbitMQ允许你将一个Queue声明成为排他性的(Exclusive Queue)。 result = self.channel.queue_declare(exclusive=True) # 随机取queue名字,发给消费端 self.callback_queue = result.method.queue # self.on_response 回调函数:只要收到消息就调用这个函数。 # 声明收到消息后就 收queue=self.callback_queue内的消息 self.channel.basic_consume(self.on_response, no_ack=True, queue=self.callback_queue) # 收到消息就调用 # ch 管道内存对象地址 # method 消息发给哪个queue # body数据对象 def on_response(self, ch, method, props, body): # 判断本机生成的ID 与 生产端发过来的ID是否相等 if self.corr_id == props.correlation_id: # 将body值 赋值给self.response self.response = body def call(self, n): # 赋值变量,一个循环值 self.response = None # 随机一次唯一的字符串 self.corr_id = str(uuid.uuid4()) # routing_key='rpc_queue' 发一个消息到rpc_queue内 self.channel.basic_publish(exchange='', routing_key='rpc_queue', properties=pika.BasicProperties( # 执行命令之后结果返回给self.callaback_queue这个队列中 reply_to = self.callback_queue, # 生成UUID 发送给消费端 correlation_id = self.corr_id, ), # 发的消息,必须传入字符串,不能传数字 body=str(n)) # 没有数据就循环收 while self.response is None: # 非阻塞版的start_consuming() # 没有消息不阻塞 self.connection.process_data_events() print("no msg...") time.sleep(0.5) return int(self.response) # 实例化 fibonacci_rpc = FibonacciRpcClient() print(" [x] Requesting fib(30)") response = fibonacci_rpc.call(10) print(" [.] Got %r" % response)