def wrapper(send_obj, message): """ :param send_obj: :param message: :return: """ # 避免循环import和局部import if message.__class__.__name__ != "OperationMessage": raise exception.ETypeMismatch("only OperationMessage can be send()") if not message.operation_id: raise exception.EMissingParam("OperationMessage need operation_id") if message.name == "SENSED_MESSAGE" or \ message.name == "DECIDED_MESSAGE" or \ message.name == "COMPLETE_MESSAGE": guardian_context = GuardianContext.get_context() try: operation = guardian_context.get_operation( message.operation_id) except KeyError: # 此处使用深拷贝,防止后续处理中造成环形引用 operation = Operation( message.operation_id, copy.deepcopy(message.params)) guardian_context.create_operation( message.operation_id, operation) operation.append_period(message.name) ret = func(send_obj, message) return ret
def wrapper(send_obj, message): """ :param send_obj: :param message: :return: """ # 避免循环import和局部import if message.__class__.__name__ != "OperationMessage": raise exception.ETypeMismatch("only OperationMessage can be send()") if not message.operation_id: raise exception.EMissingParam("OperationMessage need operation_id") if message.name == "STATE_COMPLETE_MESSAGE" or \ message.name == "PERSIST_SESSION_MESSAGE": guardian_context = GuardianContext.get_context() operation = guardian_context.get_operation( message.operation_id) finished_node = message.params["finished_node"] current_node = message.params["current_node"] timestamp = message.params["timestamp"] session = message.params["session"] if current_node: operation.add_action(current_node) if finished_node: operation.update_action( finished_node, "FINISHED", timestamp) if session: operation.update_session(session) # 状态机节点持久化 guardian_context.update_operation(operation.operation_id, operation) else: pass ret = func(send_obj, message) return ret
def patch_logging(): """ 打logging补丁 :return: """ _monkeypatch_os_fork_functions() logging = sys.modules.get('logging') if logging and getattr(logging, 'fixed_for_atfork', None): return if logging: warnings.warn('logging module already imported before patch') import logging if logging.getLogger().handlers: raise exception.ETypeMismatch('logging handlers registered before') logging._acquireLock() try: def fork_safe_createLock(self): """ 线程安全的锁 :param self: :return: """ self._orig_createLock() _atfork(self.lock.acquire, self.lock.release, self.lock.release) logging.Handler._orig_createLock = logging.Handler.createLock logging.Handler.createLock = fork_safe_createLock _atfork(logging._acquireLock, logging._releaseLock, logging._releaseLock) logging.fixed_for_atfork = True finally: logging._releaseLock()
def __init__(self, job_adapter, stage_builder=None, process_count=1): """ 初始化方法 :param JobAdapter job_adapter: 任务处理器,分级操作解析器与任务处理器绑定,完成分级任务的具体执行操作 :param StageBuilder stage_builder: 分级操作构建器 :param int process_count: 最大进程数 """ if not issubclass(job_adapter, stage.JobAdapter): raise exception.ETypeMismatch( "job_adapter is not subclass of " "JobAdapter, type:{}", format(type(job_adapter))) if stage_builder is not None and not isinstance( stage_builder, stage.StageBuilder): raise exception.ETypeMismatch("stage_builder is not instance of " "StageBuilder,type:{}".format( type(stage_builder))) super(StageStateMachineExecutor, self).__init__(None, process_count) self._stage_builder = stage_builder or stage.StageBuilder() self._bind_job_type(job_adapter)
def validate_listeners(self): """ 验证消息处理器是否符合要求。通常,我们认为一个Guardian包含的消息处理器数量应该为: 至少一个感知器、一个决策器、一个执行器。 :return: 无返回 :rtype: None :raises ETypeMismatch: 消息处理器验证失败 """ sensor_count, decision_count, executor_count = 0, 0, 0 for listener in self._listener_list: if isinstance(listener, BaseSensor): sensor_count += 1 elif isinstance(listener, BaseDecisionMaker): decision_count += 1 elif isinstance(listener, BaseExecutor): executor_count += 1 else: raise exception.ETypeMismatch("listener type is not match") if sensor_count < 1 or decision_count != 1 or executor_count != 1: raise exception.ETypeMismatch("listener must be: one decision, " "one executor, at least one sensor")
def _list_and_watch(): node_list = [] for node_name in os.listdir(path): if node_name == ".data" or node_name == ".sequence": continue if not include_data: node_list.append(node_name) else: data = self.get_data("/".join((path[len(self._base):], node_name))) node_list.append((node_name, data)) if watcher: if not callable(watcher): raise exception.ETypeMismatch("watcher must callable") with self._lock: self._ob_paths[path] = watcher return node_list
def add_node(self, node): """ 增加节点 :param Node node: 节点 :return: None :raises ETypeMismatch: 节点类型错误 :raises EInvalidOperation: 操作不合法 """ if not isinstance(node, Node): raise exception.ETypeMismatch("param node type must be Node") elif node in self._nodes: raise exception.EInvalidOperation( "node {} already added".format(node.name)) else: self._nodes.append(node) self._nodes_process[node.name] = False
def __init__(self, process_count=1): """ 初始化方法 :param int process_count: 进程数 :return: 无返回 :rtype: None :raises ETypeMismatch: 参数类型不匹配 """ if not isinstance(process_count, int) or process_count < 1 \ or process_count > 1000: raise exception.ETypeMismatch( "param process_count must be 1-1000 integer") manager = multiprocessing.Manager() self._result_queue = manager.Queue() self._concerned_message_list = ["IDLE_MESSAGE", "DECIDED_MESSAGE"] self._process_count = process_count self._process_pool = None
def on_message(self, message): """ 触发执行并返回结果,``on_execute_message`` 可能为同步或异步操作, 若为异步操作,则应返回None :param Message message: 消息对象 :return: 无返回 :rtype: None :raises ETypeMismatch: 返回值类型不匹配 :raises EMissingParam: 返回值缺字段 """ message = self.on_execute_message(message) if not message: return elif not isinstance(message, Message): raise exception.ETypeMismatch() else: log.i("execute message return:{}".format(message)) self.send(message)
def make_driver(driver_cls): """ :param driver_cls: :return: :rtype: persistence.BasePersistence """ if driver_cls == persistence.FilePersistence: driver_conf = {"STATE_SERVICE_HOSTS": "/tmp/persist"} elif driver_cls == persistence.RedisPersistence: driver_conf = {"STATE_SERVICE_HOSTS": "redis://127.0.0.1:6379/0"} elif driver_cls == persistence.ZkPersistence: driver_conf = {"STATE_SERVICE_HOSTS": "redis://127.0.0.1:6379/0"} else: raise exception.ETypeMismatch("Unknown persistence class") cfg = {"LOG_CONF_DIR": "./", "LOG_ROOT": "./log"} cfg.update(driver_conf) config.GuardianConfig.set(cfg) dv = driver_cls() return dv
def get_children(self, path, watcher=None, include_data=False): """ 获取所有子节点 :param str path: 待获取子节点的路径 :param watcher: 状态监听函数。函数形参为(event),event是一个对象,包括三个成员属性:path(发生状态变化的路径)、state(server链接状态)、type(事件类型,包括CREATED|DELETED|CHANGED|CHILD|NONE) :param bool include_data: 是否同时返回数据 :return: 子节点名字列表 :rtype: str :raises: exception.EPNoNodeError 节点不存在 :raises: exception.EPIOError IO异常 """ chd = self._valid_chd(path, include_data) if not include_data: node_list = chd.keys() else: node_list = chd.items() if watcher: if not callable(watcher): raise exception.ETypeMismatch("watcher must callable") self._new_ob(path, watcher) return node_list
def decision_logic(self, message): """ 具体决策逻辑 :param Message message: 消息对象 :return: 决策完成的消息 :rtype: Message :raises ETypeMismatch: 事件参数不匹配异常 """ log.i("begin decision logic, message:{}".format(message.name)) operation_id = message.operation_id params = message.params if self._from_key in params \ and params[self._from_key] in self._mapping: params_cp = copy.deepcopy(params) params_cp[self._to_key] = self._mapping[params_cp[self._from_key]] decided_message = framework.OperationMessage( "DECIDED_MESSAGE", operation_id, params_cp) return decided_message else: raise exception.ETypeMismatch( "{} not in params or params[{}] not in " "mapping".format(self._from_key, self._from_key))
def wrapper(send_obj, message): """ :param send_obj: :param message: :return: """ # 避免循环import和局部import if message.__class__.__name__ != "OperationMessage": raise exception.ETypeMismatch( "only OperationMessage can be send()") if not message.operation_id: raise exception.EMissingParam( "OperationMessage need operation_id") if message.name == "COMPLETE_MESSAGE": guardian_context = GuardianContext.get_context() operation = guardian_context.get_operation( message.operation_id) operation.end_operation() guardian_context.delete_operation(message.operation_id) else: pass ret = func(send_obj, message) return ret