def _frame_to_msg(self, frame): """ Method: _frame_to_msg Description: 将frame装换为AcpMessage消息 Parameter: frame: AppFrame Return: 待接受消息端的url和AcpMessage消息 Others: """ # AppFrame转换为CallAcpMsg try: msg_id = self._struct.unpack_from(frame.get_custom_bytes())[0] except: tracelog.exception("SimpleCallAcpSrv._frame_to_msg() failed. " "frame.get_custom_bytes():%s" % ( repr(frame.get_custom_bytes()))) return None, None url = frame.get_custom_bytes()[self._struct.size:] if len(url) == 0: tracelog.error("SimpleCallAcpSrv._frame_to_msg() failed. " "url is null") return None, None msg = pycallacp.AcpMessage(frame.get_cmd_code(), frame.get_data()) msg.set_msg_id(msg_id) return url, msg
def handle_cmd(self, frame): """ Method: handle_cmd Description: 注销请求处理函数,调用name_mit_manager的相应函数进行处理,然后更新本地缓存,再广播到其他APP。 Parameter: frame: 注销请求消息,数据区为AppUnRegisterRequest Return: Others: """ buf = frame.get_data() result = bf.AppUnRegisterResponse() result.init_all_attr() app = self.get_worker().get_app() try: un_reg_req = bf.AppUnRegisterRequest.deserialize(buf) tracelog.info("unregist name service:%r" % un_reg_req) except Exception: result.return_code = err_code_mgr.ER_INVALID_DESERIALIZE_STRING_ERROR result.description = err_code_mgr.get_error_msg(err_code_mgr.ER_INVALID_DESERIALIZE_STRING_ERROR , cmd='UnRegisterApp' , param_name='AppUnRegisterRequest') app.send_ack(frame, result.serialize()) tracelog.error('%s\n%s'%(result.description, buf)) return result = self.get_worker().unregister_app(un_reg_req) if un_reg_req.need_reponse is True: app.send_ack(frame, result.serialize()) return
def maintain_log_find(log_path,start_time,end_time): """ Function: maintain_log_find Description: 查找日志目录下的符合要求的日志文件,并且分类为转储日志和当前日志 Parameter: log_path: 日志文件路径 start_time: 起始时间 end_time: 截至时间 Return: current_file,dumpfile (当前文件列表,转储文件列表) Others: 无 """ current_file = [] dumpfile_map = {} dumpmatch = r'\w+_\d+_(\d{4}_(\d{2}_){4}\d{2})\.(log|zip)$' for f in os.listdir(log_path): dumptemp = re.match(dumpmatch,f) if dumptemp is not None: try: filetime = time.strptime(dumptemp.group(1), '%Y_%m_%d_%H_%M_%S') filetime = time.mktime(filetime) dumpfile_map[f] = filetime except Exception, err: tracelog.error('find unknow log: (%s)and exception %s'% (dumptemp.group(1),err)) else: current_file.append(f)
def register_handler(self, handler, *args): """ Method: register_handler Description: 注册模板handler Parameter: handler: handler对象 *args: 该handler处理的命令码 Return: Others: 命令码可以是int类型的数值,表示单个命令码 也可以是两个int组成的元组,表示一个范围内的命令码(闭区间) 例如: register_handler(handler, (100, 200)) register_handler(handler, 100) register_handler(handler, 100, 103, ...) """ if len(args) == 0: tracelog.error("no cmd range for handler %s" % handler) return for cmd_code_range in args: if isinstance(cmd_code_range, int): self.__template_cmd_handlers[cmd_code_range] = handler else: code1, code2 = cmd_code_range if code1 <= code2: for cmd_code in xrange(code1, code2 + 1): self.__template_cmd_handlers[cmd_code] = handler else: for cmd_code in xrange(code2, code1+ 1): self.__template_cmd_handlers[cmd_code] = handler
def run_case(self, app, case): """ Method: run_case Description: 运行一个用例 Parameter: case: 一个用例, instance of ALECase Return: 0: 成功 非0: 失败 Others: """ tracelog.info("run case %s..." % str(case)) ret = self.find_case_entity(case) if ret != 0: return -1 case.case_entity frame = bf.AppFrame() frame.set_cmd_code(case.case_entity.get_cmd_code()) frame.add_data(case.case_entity.gen_request()) frame.set_receiver_pid(app.get_pid("AleGate")) ack_frames = bf.rpc_request(frame, case.case_entity.get_timeout()) if len(ack_frames) == 0: tracelog.error("wait for response timeout. case:%s" % str(case)) else: case.case_entity.handle_ack(ack_frames[0].get_data()) return 0
def __unbind_virtual_ip(self, write_log): """ Method: __unbind_virtual_ip Description: 解除绑定的虚拟ip Parameter: write_log: 解除绑定虚拟ip失败时,是否需要记录日志 Return: 错误码 Others: """ if self.__cluster_cfg_info.virtual_cluster_ip == "": return ret, msg = unbind_virtual_ip(self.__cluster_cfg_info.virtual_cluster_ip , self.__cluster_cfg_info.virtual_cluster_mask , self.__cluster_cfg_info.external_NIC) if ret != 0 and write_log: tracelog.error("unbind_virtual_ip(%s/%s on %s) failed:%d, %s" % ( self.__cluster_cfg_info.virtual_cluster_ip , self.__cluster_cfg_info.virtual_cluster_mask , self.__cluster_cfg_info.external_NIC , ret , msg)) return ret
def __switch_to_slave(self): """ Method: __switch_to_slave Description: 将角色切换到slave Parameter: 无 Return: Others: """ # 切换到slave old_role = self.__role old_state = self.__state self.__role = CLUSTER_ROLE_SLAVE self.__state = CLUSTER_STATE_NORMAL tracelog.info("the current cluster node %s switch to slave. state:%d" % ( self.__cluster_cfg_info.my_inner_ip , state)) ret_code = self.__unbind_virtual_ip(True) if ret_code != 0: tracelog.error("unbind virtual ip faild. ret_code:%d" % ret_code) self.__cluster_node.on_state_change(old_role, old_state, self.__role, state)
def load(self, cfg_file_path): """ Method: load Description: 从指定的配置文件中加载设备配置信息 Parameter: cfg_file_path: 配置文件的路径 Return: 错误码 Others: """ ret = 0 try: xmldoc = ET.parse(cfg_file_path) xmlroot = xmldoc.getroot() ret = self.__load_device_info(xmlroot) if ret == 0: ret = self.__load_cluster_info(xmlroot) if ret != 0: tracelog.error("load device configuration failed. cfg_file_path:%s" % cfg_file_path) except: tracelog.exception("load device configuration failed. cfg_file_path:%s" % cfg_file_path) return -1 return ret
def reset_NE_state(self): """ Method: reset_NE_state Description: 重置网元的状态 Parameter: 无 Return: 错误码 Others: 将全同步未结束的,都设置为需要全同步。本接口在进程启动初始化时调用 """ # mit启动时,将那些之前状态为非normal的,设置为normal, # 并且是否需要同步设置为1 multisql = mit.MultiSQL() multisql.set_oracle_sql(('update tbl_NEDbSyncState ' 'set "need_sync_full"=1, "sync_state"=%d ' 'where "sync_state"<>%d') % ( db_sync_update_const.NE_STATE_NORMAL , db_sync_update_const.NE_STATE_NORMAL)) multisql.set_sqlite_sql(('update tbl_NEDbSyncState ' 'set [need_sync_full]=1, [sync_state]=%d ' 'where [sync_state]<>%d') % ( db_sync_update_const.NE_STATE_NORMAL , db_sync_update_const.NE_STATE_NORMAL)) ret = self.raw_exec_ex("NEDbSyncState", multisql) if ret.get_err_code() != 0: tracelog.error("update tbl_NEDbSyncState failed. %d, %s" % ( ret.get_err_code() , ret.get_msg())) return ret.get_err_code() return 0
def __load_device_info(self, xmlroot): """ Method: __load_device_info Description: 从配置文件中加载设备信息 Parameter: xmlroot: xml解析后的ET结构 Return: 错误码 Others: """ dev_ele = xmlroot.find("device") if dev_ele is None: tracelog.error("'device' element not found!") return -1 dev_id = dev_ele.get("id", "").strip().encode("utf-8") if dev_id == "": tracelog.error("'device.id' is not configured!") return -1 self.__device_id = dev_id nic = dev_ele.get("external_NIC", "").strip() self.__device_external_NIC = nic.encode("utf-8") nic= dev_ele.get("internal_NIC", "").strip() #if nic == "": # tracelog.error("'device.internal_NIC' is not configured!") # return -1 self.__device_internal_NIC = nic.encode("utf-8") return self.init_ip_from_os()
def __load_cluster_info(self, xmlroot): """ Method: __load_cluster_info Description: 从XML结构中,解析得到设备的信息 Parameter: xmlroot: ET结构,xml的根节点 Return: Others: """ cluster_ele = xmlroot.find("cluster") if cluster_ele is None: tracelog.error("'cluster' element not found!") return -1 enable = cluster_ele.get("enable", "").strip() if enable == "": tracelog.error("'cluster.enable' is not configured!") return -1 self.__cluster_enable = int(enable) self.__cluster_virtual_ip = cluster_ele.get("virtual_ip", "").strip() self.__cluster_virtual_mask = cluster_ele.get("virtual_mask", "").strip() self.__cluster_max_nodes_num = int(cluster_ele.get("max_nodes_num", "0").strip()) return 0
def del_iptables_rule(self,rule): """ Method: del_iptables_rule Description: 删除防火墙设置的原子操作 Parameter: rule: 防火墙规则,是个三元组,格式如下("网卡名称","tcp或udp","端口号") Return: 0代表成功,1代表失败 Others: 无 """ #删除 return_code = os_execute("iptables -D INPUT -i %s -p %s --dport %s -j ACCEPT" %( rule[0],rule[2],rule[1])) if return_code !=0: tracelog.error('Fail to del iptables rule') return 1 else: tracelog.info('iptables rule deleted and info is %s card %s port %s treaty'%( rule[0],rule[2],rule[1])) return_code = os_execute("service iptables save") if return_code !=0: tracelog.error('Fail to save iptables rule') return 1 else: tracelog.info('Success to save iptables') return 0
def __call_oracle_imp(self): """ Method: __call_oracle_imp Description: 调用oracle的impdp命令 Parameter: 无 Return: 错误码 Others: """ mocs = self.get_worker().get_app().get_synchronized_mocs() tables = ["tbl_"+moc.get_moc_name() for moc in mocs.itervalues()] timeout = len(tables)*300 + 300 # 秒 db_file_dir = os.path.join(self.get_worker().get_app().get_app_top_path() , db_sync_common_const.DB_SYNC_DIR ) ret = call_oracle_cmd.call_impdp(tables , db_file_dir , timeout) if ret != 0: tracelog.error("call_impdp failed. ret:%d" % ret) return -1 return 0
def start_listen(self): """ Method: start_listen Description: 开始监听 Parameter: 无 Return:错误码 Others: """ if self._ssl_option is None: ret = self.bind("", self._port) else: ret = self.bind_with_ssl("" , self._port , self._ssl_option.get("key_file", "") , self._ssl_option["cert_file"] , self._ssl_option["proto_version"]) if ret == 0: tracelog.info("SimpleCallAcpSrv start listen on port %d, ssl_option:%s"%( self._port , self._ssl_option)) else: tracelog.error("SimpleCallAcpSrv listen on port %d failed, ssl_option:%s"%( self._port , self._ssl_option)) return ret
def __add_node(self, node_ip, is_enable): """ Method: __add_node Description: 增加节点 Parameter: node_ip: 节点的ip is_enable: 是否启用了 Return: 错误码 Others: """ ret = 0 if node_ip == self.__cluster_cfg_info.my_inner_ip: return ret for node in self.__other_nodes: if node.get_ip() == node_ip: break else: node_info = ClusterNodeInfo(node_ip) if is_enable == 0: node_info.set_enable(False) self.__other_nodes.append(node_info) url = self.__get_url(node_ip) ret = self.__callacp_client.new_connect(url) if ret != 0: tracelog.error("new connection to cluster node failed. %s" % url) return ret
def handle_cmd(self, frame): """ Method: handle_cmd Description: 处理消息 Parameter: frame: AppFrame Return: 无 Others: """ para = cluster_msg_def.RmvClusterNodeRequest.deserialize(frame.get_data()) if para is None: tracelog.error("invalid request! frame:%s" %(frame)) return rep = cluster_msg_def.RmvClusterNodeResponse() cur_cluster = self.get_worker().get_cur_cluster() if cur_cluster is None: rep.return_code = err_code_mgr.ER_CLUSTER_IS_DISABLE rep.description = err_code_mgr.get_error_msg(err_code_mgr.ER_CLUSTER_IS_DISABLE) else: rep.return_code, rep.description = cur_cluster.rmv_node(para.ip) # 发送应答 self.get_worker().send_ack(frame,rep.serialize())
def on_msg_received(self, url_or_srv_name, msg): """ Method: on_msg_received Description: "收到消息"的处理接口 Parameter: url_or_srv_name: 消息发送者的url msg: 消息 Return: Others: """ #print "on_msg_received", msg.get_cmd_code() cmd_code = msg.get_cmd_code() if (cmd_code != cluster_cmd_code.CMD_CLUSTER_QUERY_STATE and cmd_code != cluster_cmd_code.CMD_CLUSTER_ACK_STATE): tracelog.error("ClusterServerEventHandler receved invalid msg:%d" % cmd_code) return try: state_msg = ClusterStateMsg.deserialize(msg.get_data()) if state_msg is None: tracelog.error("ClusterStateMsg.deserialize failed. " "msg:%d, %r" % (cmd_code, msg.get_data())) return if cmd_code == cluster_cmd_code.CMD_CLUSTER_QUERY_STATE: self.__cluster_thread.on_query_state(url_or_srv_name, state_msg) elif cmd_code == cluster_cmd_code.CMD_CLUSTER_ACK_STATE: self.__cluster_thread.on_ack_state(state_msg) except: tracelog.exception("handler msg(%d) failed" % cmd_code)
def handle_cmd(self, frame): """ Method: handle_cmd Description: 请求处理函数,如果EventQueryRequest对象反序列化成功,进行必要的参数检查, 然后调用事件查询处理器,查询事件记录数,和指定分页的记录,返回给查询者。 Parameter: frame: 请求消息,data中为EventQueryRequest对象 Return: 无 Others: """ buf = frame.get_data() tracelog.info('EventQueryHandler data %s'%buf) result = message_across_app.EventQueryResponse() result.init_all_attr() result.count = 0 result.event_query_result = [] try: req = message_across_app.EventQueryRequest.deserialize(buf) except Exception, err: tracelog.error('EventQueryHandler deserialize exception: %s'%err) result.user_session = '' result.return_code = err_code_mgr.ER_INVALID_DESERIALIZE_STRING_ERROR result.description = err_code_mgr.get_error_msg(err_code_mgr.ER_INVALID_DESERIALIZE_STRING_ERROR , cmd='EventQuery' , param_name='EventQueryRequest') result.count = 0 result.event_query_result = [] self.send_ack(frame, (result.serialize(), )) return
def __switch_to_master(self, state): """ Method: __switch_to_master Description: 将角色切换到master Parameter: state: 状态 Return: Others: """ # 切换到master old_role = self.__role old_state = self.__state self.__mater_node_info.update(self.__cluster_cfg_info.my_inner_ip, self.__start_time) self.__role = CLUSTER_ROLE_MASTER self.__state = state tracelog.info("the current cluster node %s switch to master. state:%d" % ( self.__cluster_cfg_info.my_inner_ip , state)) ret_code = self.__bind_virtual_ip(True) if ret_code != 0: tracelog.error("bind virtual ip faild. ret_code:%d" % ret_code) self.__cluster_node.on_state_change(old_role, old_state, self.__role, state) # 进入master状态后,重新设置其他节点的状态 self.__reset_query_counter(True)
def __handle_full_sync_ntf(self, frame, ne_id, sync_object, event): """ Method: __handle_full_sync_ntf Description: 处理全同步事件通知 Parameter: frame: 数据帧 ne_id: 网元的ID sync_object: 同步传输对象 event: 事件通知 Return: Others: """ tracelog.info('receive full sync notification from NE(%d)' % ne_id) error_code = NEInfoMgr.set_ne_need_sync_full(ne_id , self.get_worker().get_app().get_mit_manager() , True) if error_code != 0: tracelog.error("set_ne_need_sync_full() failed: %d" % error_code) # 不给EAU回应答;EAU收到收不到应答后,下次重试 return result = DBSyncResult() result.id = sync_object.id result.return_code = error_code result.error_message = '' result.event_ids = [] self.__send_ack(frame, result.serialize())
def register_ack_handler_again(self, handler, task_id): """ Method: register_ack_handler_again Description: 重新将handler注册为等待应答消息的状态 Parameter: handler: handler对象 task_id: 任务号 Return: 任务号 Others: """ if handler is None: tracelog.error("register ack in worker %s handler is null!" % self.get_name()) return CmdWorker.invalid_task_id if task_id == CmdWorker.invalid_task_id: task_id = self.__new_task_id() if task_id < self.__min_task_id or task_id > self.__max_task_id: tracelog.error("worker %s task_id %d is out of range(%d, %d)!" % (self.get_name(), task_id, self.__min_task_id, self.__max_task_id)) return CmdWorker.invalid_task_id self.__ack_handlers[task_id] = handler self.register_time_out_handler(handler) return task_id
def __send_request_to_ne(self): """ Method: __send_request_to_ne Description: 发送导出命令给网元 Parameter: 无 Return: Others: """ ne_pid = NEInfoMgr.get_ne_pid_by_id(self.ne_id) if ne_pid is None: tracelog.error("get_ne_pid_by_id(%d) failed." % self.ne_id) return req = db_sync_base.SyncFullRequest() req.ne_id = self.ne_id req.ftp_ip = self.get_worker().get_app().get_device_cfg_info().get_device_external_ip() req.ftp_port = db_sync_update_const.FTP_SERVER_PORT req.file_path = db_sync_update_const.NE_DB_DUMP_COMPRESSED_PATH % self.ne_id # 位于data/ftp目录中 req.ftp_user = "******" # TODO req.ftp_pwd = "ftp_user" # TODO frame = bf.AppFrame() frame.set_cmd_code(cmd_code_def.CMD_SYNC_NE_EXP_FULL) frame.add_data(req.serialize()) frame.set_receiver_pid(ne_pid) frame.set_next_pid(self.get_worker().get_pid("EAUGate")) mocs = self.get_worker().get_app().get_synchronized_mocs() timeout = len(mocs)*400 + 400 self.wait_for_ack(frame, timeout) # 超时时间,单位秒
def over(self, result, **args): """ Method: over Description: 将handler设置为结束状态 Parameter: result: 错误码 args: 错误信息中需要用到的一些参数 Return: Others: """ self._worker.unregister_time_out_handler(self) if not self.__over: self.__over = True self.__result = result self.__result_args = args for child in self.__children: child.over(result, **args) self._on_over(result, **args) if self.__parent: self.__parent._on_child_over(self) else: tracelog.error("handler %r is over before, " "result is %d, new result is %d" % ( self, self.__result, result)) return self
def time_out(self): processors = self.get_worker().get_app().get_sub_man_worker().get_state_manager().get_processors() for pro in processors: if len(pro.get_target().get_spec().fake_id) > 0: tracelog.info('subscriber(openid %s, fakeid %s), update the detail info' % (pro.get_target().get_spec().subscriber_open_id, pro.get_target().get_spec().fake_id)) sub_info_buf = self.get_worker().get_app().get_wx_service_api().get_subscriber_info(pro.get_target().get_spec().fake_id) sub_info = json.loads(sub_info_buf) # 更新processor和mit if sub_info['Sex'] == '1': gender = '男'.decode('gbk').encode('utf-8') else: gender = '女'.decode('gbk').encode('utf-8') pro.get_target().set_detail_info(sub_info['Username'], sub_info['NickName'], gender, sub_info['City']) subs = self.get_worker().get_app().get_mit_manager().rdm_find('Subscriber', subscriber_open_id = pro.get_target().get_spec().subscriber_open_id) if len(subs) == 0: tracelog.error('subscriber(openid %s) in processor does not exist in mit!' % pro.get_target().get_spec().subscriber_open_id) else: subs[0].weixin_id = sub_info['Username'] subs[0].nickname = sub_info['NickName'] subs[0].gender = gender subs[0].city = sub_info['City'] self.get_worker().get_app().get_mit_manager().rdm_mod(subs[0]) head_img_file = msg_params_def.PORTAL_IMG_FILE_LOCAL_PATH_PREFIX + msg_params_def.WX_HEAD_IMG_FILE_SAVE_LOCAL_PATH + subs[0].subscriber_open_id + '.png' self.get_worker().get_app().get_wx_service_api().save_head_img(subs[0].fake_id, head_img_file) time.sleep(5)
def on_msg_received(self, url_or_srv_name, msg): #print "on_msg_received:", msg.get_cmd_code(), url_or_srv_name, msg.get_data(), msg.get_msg_id() cmd_code = msg.get_cmd_code() if cmd_code == bf.CMD_QUERY_CLUSTER_MASTER_IP: rep = bf.QueryClusterMasterIpResponse() rep.ip = self.__name_server.get_cluster_master_ip() elif cmd_code == bf.REGISTER_NAME_COMMAND: try: req = bf.AppRegisterRequest.deserialize(msg.get_data()) except: tracelog.exception("AppRegisterRequest deserialize failed.") return rep = self.__name_server.register_app(req) if rep.return_code == 0: tracelog.info("app regist name service: %r, pid:%r" % (req, rep.app_info.pid)) else: tracelog.error("app regist name service failed: %r" % req) ack_msg = pycallacp.AcpMessage(pycallacp.CMD_ACK_MSG, rep.serialize()) ack_msg.set_msg_id(msg.get_msg_id()) self._callacp_inst.send(url_or_srv_name, ack_msg)
def on_query_state(self, url, msg): """ Method: on_query_state Description: "查询状态"的处理接口 Parameter: url: 发送查询者的url(对端的url) msg: 查询消息 Return: Others: """ try_times = 1 with self.__lock: while try_times <= 2: for node in self.__other_nodes: if node.get_ip() == msg.ip: node.on_heartbeat(msg) try_times = 3 break else: if try_times == 2: tracelog.error("the cluster node %s is unknown" % msg.ip) else: # 重新从DB中加载节点信息 tracelog.error("receive state query cmd from unknown " "node:%s now try to reload nodes" % msg.ip) self.reload_nodes() try_times += 1 # 发送应答消息 ack_msg = self.__get_state_msg(cluster_cmd_code.CMD_CLUSTER_ACK_STATE) self.__callacp_srv.send(url, ack_msg)
def _ready_for_work(self): """ Method: _ready_for_work Description: 线程工作前的初始化函数 Parameter: 无 Return: 0: 成功 非0: 失败 Others: """ self.__doing_what = WorkThread.doing_ready_for_work for wrkr in self.__workers: try: ret = wrkr.ready_for_work() except: tracelog.exception("worker %s ready_for_work failed." % wrkr.get_name()) return -1 if ret == 0: tracelog.info("%s is ready for work." % wrkr.get_name()) else: tracelog.error("%s is not ready." % wrkr.get_name()) return ret return 0
def rmv_node(self, ip): """ Method: rmv_node Description: 删除指定的节点 Parameter: ip: 指定的节点的ip Return: 错误码,错误信息 Others: """ online_err = (err_code_mgr.ER_CANNOT_RMV_ONLINE_CLUSTER_NODE , err_code_mgr.get_error_msg(err_code_mgr.ER_CANNOT_RMV_ONLINE_CLUSTER_NODE)) with self.__lock: # 只允许删除离线的节点 if ip == self.__cluster_cfg_info.my_inner_ip: return online_err for node in self.__other_nodes: if node.get_ip() == ip and node.is_online(): return online_err # 先删除mit中的信息 ret_code, err_msg = self.__mit.rmv_node(ip) if ret_code == 0: # 删除内存中的信息 self.__rmv_node(ip) tracelog.info("remvoe node %s." % ip) else: tracelog.error("remvoe node %s failed." % ip) return ret_code, err_msg
def maintain_log_currentfile_zip(location,log_path,task_no,current_file): """ Function: maintain_log_currentfile_zip Description: 打包压缩当前日志文件 Parameter: location: 压缩文件路径 log_path: 日志文件路径 task_no: 打包任务号 current_file: 当前文件列表 Return: 无 Others: 无 """ openfile = None openzipfile = None log_file = None for f in current_file: try: temp_file_name = '%s_%s.log'%(f[:-4],time.strftime("%Y_%m_%d_%H_%M_%S")) openfile = open(os.path.join(log_path,f),'r') log_file = openfile.read() except Exception, err: tracelog.error('log export task %d %s'%(task_no,err)) continue finally:
def dispatch_frame_to_duty_worker(self, frame, multi_worker=False): """ Method: dispatch_frame_to_duty_worker Description: 将appframe发送到需要处理该消息的worker Parameter: frame: AppFrame multi_worker: frame是否会被多个worker处理 Return: Others: """ threads = [] with self.__mutex: for thread in self.__my_threads: for worker in thread.get_workers(): if worker.is_my_duty(frame): threads.append(thread) if multi_worker is False: break else: continue break if len(threads) > 0: self.__dispatch_frame(threads, frame) else: tracelog.error("dispatch frame to duty worker failed.%s" % str(frame))