def _run_catch(self, func, path, path_is_dir=False): """ 执行func并捕获异常,将文件系统异常转换为对应的异常对象 """ ospath = self._base + path try: if os.path.exists(ospath): if path_is_dir: if os.path.isdir(ospath): return func() else: if os.path.isfile(ospath): # 判断文件是否过期,过期直接报错 mtime = os.stat(ospath).st_mtime if mtime < time.time() - self._timeout: self.delete_node(path, True) else: return func() else: return func() raise exception.EPNoNodeError() except exception.EPNoNodeError as e: log.r(e, "Node not exist:{}".format(path)) except Exception as e: log.r(exception.EPIOError(), "Request I/O Error")
def _run_catch(cls, func, path, path_is_dir=False): """ 执行func并捕获异常,将kazoo异常转换为对应的异常对象 """ try: if not os.path.exists(path) or (path_is_dir and not os.path.isdir(path)): raise exception.EPNoNodeError() return func() except exception.EPNoNodeError as e: log.r(e, "Node not exist:{}".format(path)) except: log.r(exception.EPIOError(), "Request I/O Error")
def _run_catch(cls, func): """ 执行func并捕获异常,将kazoo异常转换为对应的异常对象 """ import kazoo try: return func() except kazoo.interfaces.IHandler.timeout_exception: raise exception.EPConnectTimeout() except kazoo.exceptions.NoNodeError: raise exception.EPNoNodeError() except: log.r(exception.EPIOError(), "Request I/O Error")
def del_listener(self, listener): """ 删除一个消息处理器 :param Listener listener: 消息处理器 :return: 无返回 :rtype: None :raises ValueError: 消息处理器不存在 """ try: self._listener_list.remove(listener) del self._listener_table[listener] except ValueError as e: log.r(e, "del listener failed")
def create_node(self, path, value="", ephemeral=False, sequence=False, makepath=False): """ 根据节点各属性创建节点 :param str path: 节点路径 :param str value: 待存数据 :param bool ephemeral: 是否是临时节点 :param bool sequence: 是否是顺序节点 :param bool makepath: 是否创建父节点 :return: None :raises: exception.EPNoNodeError 节点不存在 :raises: exception.EPIOError IO异常 """ path = self._base + path try: if ephemeral: # 临时节点,直接用文件来表示 dirname = os.path.dirname(path) if not os.path.exists(dirname): if makepath: os.makedirs(dirname, self._mode) else: raise exception.EPNoNodeError file_path = path if sequence: file_path = FilePersistence._seq_file_name(path) with open(file_path, 'w') as f: f.write(value) with self._lock: self._touch_paths[file_path] = "" else: # 实体节点,用目录来表示,数据存放在目录下的.data文件中 if not os.path.exists(path): if not os.path.exists(os.path.dirname(path)) and not makepath: raise exception.EPNoNodeError os.makedirs(path, self._mode) file_path = "/".join((path, ".data")) with open(file_path, 'w') as f: f.write(value) except exception.EPNoNodeError as e: log.r(e, "Node not exist:{}".format(os.path.dirname(path))) except: log.r(exception.EPIOError(), "Request I/O Error") log.d("create node success, path:{path}, value:{value}, ephemeral:" "{ephemeral}, sequence:{sequence}, makepath:{makepath}".format( path=path, value=value, ephemeral=ephemeral, sequence=sequence, makepath=makepath))
def _run_catch(cls, func): """ 执行func并捕获异常,将kazoo异常转换为对应的异常对象 """ import kazoo try: return func() except kazoo.exceptions.NoNodeError: raise exception.EPNoNodeError() except kazoo.exceptions.ZookeeperError: log.f("zk fail") raise exception.EPServerError() except Exception as e: log.r(exception.EPIOError(), "Requesst I/O Error")
def _run_catch(cls, func, path="", path_is_dir=False): """ 执行func并捕获异常,将kazoo异常转换为对应的异常对象 """ import redis # noinspection PyBroadException try: return func() except redis.exceptions.ConnectionError: raise exception.EPConnectTimeout() except exception.EPNoNodeError as e: raise e except Exception as e: log.r(exception.EPIOError(), "Request I/O Error")
def active(self): """ 感知器生效函数。该函数创建新线程,定期进行外部事件拉取操作 :return: 无返回 :rtype: None :raises ThreadError: 创建线程失败 """ try: self._pull_thread = threading.Thread( target=self.event_dealer) self._pull_thread.daemon = True self._pull_thread.start() except threading.ThreadError as e: log.r(e, "create new thread err")
def active(self): """ 重载感知器生效函数,加入自动刷新线程的生效操作。 :return: 无返回 :rtype: None :raises ThreadError: 创建线程失败 """ super(CronSensor, self).active() try: self._reload_thread = threading.Thread(target=self._reload) self._reload_thread.daemon = True self._reload_thread.start() except threading.ThreadError as e: log.r(e, "create new thread err")
def start(self): """ 启动状态机 :return: None :raises EStatusMismatch: 状态不匹配 :raises Exception: 通用异常 """ self.prepare() if self._status == self.Status.INITED \ or self._status == self.Status.PAUSED: self._status = self.Status.RUNNING else: raise exception.EStatusMismatch( "Only in inited or paused status can call " "this method.current status:{}".format(self._status)) while self._status == self.Status.RUNNING: try: self.run_next() except Exception as e: self._status = self.Status.FAILED log.r(e, "start fail in run_next")
def save_context(self): """ 运行数据持久化,当当前Guardian为主(lock属性为True)时,可持久化数据,否则失败 :return: 无返回 :rtype: None :raises EInvalidOperation: 非法操作 """ if not self.lock: log.e("current guardian instance no privilege to save context") raise exception.EInvalidOperation( "current guardian instance no privilege to save context") context_path = config.GuardianConfig.get_persistent_path("context") context_to_persist = self operations_tmp = self.operations context_to_persist.operations = {} try: persistence.PersistenceDriver().save_data(context_path, pickle.dumps(context_to_persist)) except Exception as e: self.operations = operations_tmp log.r(e, "save context fail") self.operations = operations_tmp log.d("save context success")
def start(self): """ 带有持久化功能的状态机启动执行。状态机启动后,会根据每个节点执行的返回值,执行下一个节点,直到返回 结束或执行异常。在每个节点执行完成后,会向结果队列中发送消息,由主进程进行处理 :return: 无返回 :rtype: None """ session = self.session while True: control_id, control_message = self._helper.get_control_message(session) if control_id is not None: # 状态机第一次处理控制消息或控制消息为最新还没被处理 if session.last_control_id is None \ or session.last_control_id != control_id: control_message_cp = copy.deepcopy(control_message) session.last_control_id = copy.deepcopy(control_id) else: control_message_cp = None else: control_message_cp = None # session中的控制消息应在处理完成之后被清理 session.control_message = control_message_cp if session.control_message is not None: # 感知到控制消息后要强制持久化session,避免控制消息丢失 self._helper.persist( reason=PersistedStateMachineHelper.Reason.CONTROL, session=session, finished_name=None, next_name=None ) # 第一次运行的状态机,记录第一个节点信息 if self.status == self.Status.INITED: todo_params = self.dump() todo_node_name = todo_params["current_node"] self._helper.persist( reason=PersistedStateMachineHelper.Reason.STARTED, session=session, finished_name=None, next_name=todo_node_name ) self.status = self.Status.RUNNING if self.status == self.Status.RUNNING: try: finished_node_name = self.dump()["current_node"] self.run_next() session.nodes_process[finished_node_name] = True finished_state = self.dump() todo_node_name = finished_state["current_node"] session.status = finished_state["status"] if self.status == self.Status.FINISHED: session.current_node = None else: session.current_node = self. \ get_node(todo_node_name) session.nodes_process = copy.copy( finished_state["nodes_process"]) # 节点变更或需要强制刷新 if finished_node_name != todo_node_name or session.reset_flush(): self._helper.persist( reason=PersistedStateMachineHelper.Reason.NODE_CHANGED, session=session, finished_name=finished_node_name, next_name=todo_node_name ) except Exception as e: self.status = self.Status.FAILED log.r(e, "start fail in running") else: break