基于RabbitMQ的direct任务驱动异步RPC程序实现:
RPC_dispatcher指令分发器:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 __Author__ = "Zhang Xuyao" 4 5 import pika 6 import uuid 7 import time 8 import threading 9 10 11 class RpcDispatcher(object): 12 def __init__(self, rMQ_addr): 13 self.cmd_list = [ 14 "ls", "df", "free", 15 "ip", "ifconfig", "tail", 16 "head", "grep", "uptime", 17 "date" 18 ] 19 self.task_dict = {} 20 self.task_fin_dict = {} 21 self.routing_key_list = [] 22 23 self.connection = pika.BlockingConnection( 24 pika.ConnectionParameters(host=rMQ_addr) 25 ) 26 self.channel = self.connection.channel() 27 28 # 收数据用 29 recv_queue = self.channel.queue_declare(exclusive=True) 30 self.recv_queue_name = recv_queue.method.queue 31 self.channel.basic_consume(self._on_response, queue=self.recv_queue_name) 32 33 # 发数据用 34 self.channel.exchange_declare(exchange='send', type='direct') 35 self.send_queue = self.channel.queue_declare() 36 self.send_queue_name = self.send_queue.method.queue 37 38 # 获取指定通道的响应(4)### 39 def _on_response(self, ch, method, parameters, msg): 40 if parameters.correlation_id in self.task_dict: 41 self.task_dict[parameters.correlation_id][parameters.app_id]["response"] = msg.decode("utf-8") 42 ch.basic_ack(delivery_tag=method.delivery_tag) 43 self.task_dict[parameters.correlation_id][parameters.app_id]["recv_time"] = time.time() 44 fin_flag = False 45 for host in self.task_dict[parameters.correlation_id]: 46 if self.task_dict[parameters.correlation_id][host]["response"] != None: 47 continue 48 else: 49 50 break 51 # 执行结果全部收到就把记录转移到已经完成容器中,根据检查已经完成容器中的内容用于确定任务的状态 52 else: 53 self.task_fin_dict[parameters.correlation_id] = self.task_dict[parameters.correlation_id] 54 del self.task_dict[parameters.correlation_id] 55 56 # 发送请求(2)###### 57 def _on_request(self, input_cmd, host_list): 58 print(RpcDispatcher.colorStr("[x]Requesting>>: '%s' on %s" 59 % (cmd, tuple(host_list)), 33)) 60 self.response = None 61 # 生成全局校验码 62 corr_id = str(uuid.uuid4()) 63 print(RpcDispatcher.colorStr("[x]Task_id>>: %s" 64 % corr_id, 34)) 65 self.task_dict[corr_id] = {} 66 if host_list: 67 for host in host_list: 68 self.task_dict[corr_id][host] = { 69 "cmd": input_cmd, 70 "response": None, 71 "req_time": time.time(), 72 "recv_time": None, 73 } 74 # 绑定routing_key准备并发布消息 75 self.channel.queue_bind(exchange='send', 76 queue=self.send_queue_name, 77 routing_key=host) 78 # 向执行器并发布消息指令 79 self.channel.basic_publish(exchange='send', 80 routing_key=host, 81 properties=pika.BasicProperties( 82 reply_to=self.recv_queue_name, 83 correlation_id=corr_id, 84 ), 85 body=str(input_cmd)) 86 # 消息发布后解除routing_key绑定 87 self.channel.queue_unbind(exchange='send', 88 queue=self.send_queue_name, 89 routing_key=host) 90 91 # 守护线程负责不断检测响应结果是否全部收到 92 on_recv_thread = threading.Thread(target=self._on_recv, args=[corr_id, ]) 93 on_recv_thread.setDaemon(True) 94 on_recv_thread.start() 95 96 # 等待数据消息(3) 97 def _on_recv(self, task_id): 98 # 根据检查已经完成容器中的指定task_id是否存在来确定任务的状态,为空则继续收取消息 99 while task_id not in self.task_fin_dict: 100 self.connection.process_data_events() 101 102 # 显示已经完成的任务编号(5) 103 def show_task_fin(self): 104 print("尚未查看的任务:") 105 for task_id in self.task_fin_dict: 106 value_list = tuple(self.task_fin_dict[task_id].values()) 107 host_list = tuple(self.task_fin_dict[task_id].keys()) 108 cmd = str(value_list[0]["cmd"]) 109 print(RpcDispatcher.colorStr("[task_id]: %s | [cmd_info]: '%s' | [host_list]: %s" 110 % (task_id, cmd, host_list), 32)) 111 112 # 获取指定任务的执行结果(6) 113 def get_response(self, task_id): 114 if task_id in self.task_fin_dict: 115 for host in self.task_fin_dict[task_id]: 116 response = self.task_fin_dict[task_id][host]["response"] 117 cmd_req = self.task_fin_dict[task_id][host]["cmd"] 118 time_cost = self.task_fin_dict[task_id][host]["recv_time"] - 119 self.task_fin_dict[task_id][host]["req_time"] 120 time_cost = round(time_cost, 3) 121 print(RpcDispatcher.colorStr("Host: %s | Cmd: '%s' Time Cost: %ss | Response: " 122 % (host, cmd_req, time_cost), 33)) 123 print(RpcDispatcher.colorStr(response, 36)) 124 del self.task_fin_dict[task_id] 125 else: 126 print("任务结果尚未全部返回") 127 128 # 接收外部输入,调用请求(1) 129 def call(self, cmd, host_list): 130 return self._on_request(cmd, host_list) 131 132 @staticmethod 133 def colorStr(aStr, color_code): 134 return "