def _output_result(self, rs): """将result对象按照json的格式输出 """ self.set_header('Content-Type', 'application/json;charset=utf-8') self.set_status(rs.status_code) self.write(to_json(rs)) self.finish()
def create_flow_template(self, flow_meta_name, name, bind_args, max_run_instance, creator) -> Result: """创建flow_template """ # 获取flow_meta以及检查其存在性 try: flow_meta = self._flow_meta_mgr.get(flow_meta_name) except ObjectNotFoundException: raise BadReq("flow_meta_not_exist", flow_meta=flow_meta_name) # 检查name是否已经存在 if self._flow_tpl_dao.is_name_existed(name): raise BadReq("name_already_exist", name=name) # 检查creator是否存在 creator_user = self._user_dao.query_user_by_id(creator) if not creator_user: raise BadReq("invalid_creator_id", creator=creator) # 校验参数 rs = self._validate_tpl_bind_args(flow_meta, bind_args) if rs.status_code == Result.STATUS_BADREQUEST: return rs bind_args = rs.data created_on = datetime.datetime.now() # 插入吧! flow_template = self._flow_tpl_dao.insert_flow_template( flow_meta_name, name, json.dumps(bind_args), max_run_instance, creator, created_on) log.acolyte.info("New flow template created, {}".format( to_json(flow_template))) # 返回刚创建的View return Result.ok(data=FlowTemplateView.from_flow_template( flow_template, creator_user))
def start_flow(self, flow_template_id: int, initiator: int, description: str, start_flow_args: Dict[str, Any]) -> Result: """开启一个flow进程,创建flow_instance并执行第一个Job S1. 根据flow_template_id获取flow_template,然后获取flow_meta,如果获取失败,返回错误 S2. 检查并合并参数 S3. 检查max_run_instance S4. 创建一条新的flow_instance记录 S5. 创建context S6. 回调flow meta中on_start方法的逻辑 :param flow_template_id: 使用的flow template :param initiator: 发起人 :param description: 本次flow描述 :param start_flow_args: 执行FlowMeta的on_start方法时所需要的参数 """ if start_flow_args is None: start_flow_args = {} # 检查flow_template_id是否合法 flow_template = self._flow_tpl_dao.query_flow_template_by_id( flow_template_id) if flow_template is None: raise BadReq("invalid_flow_template", flow_template_id=flow_template_id) flow_meta = self._flow_meta_mgr.get(flow_template.flow_meta) if flow_meta is None: raise BadReq("invalid_flow_meta", flow_meta=flow_meta) # 检查发起者 initiator_user = self._user_dao.query_user_by_id(initiator) if initiator_user is None: raise BadReq("invalid_initiator", initiator=initiator) # 检查并合并start_flow_args field_rules = getattr(flow_meta.on_start, "field_rules", []) rs = self._combine_and_check_args("start", field_rules, start_flow_args, flow_meta.start_args) if rs.status_code == Result.STATUS_BADREQUEST: return rs start_flow_args = rs.data # 锁定检查instance数目并创建第一条记录 flow_instance = None if flow_template.max_run_instance > 0: lock_key = "lock_instance_create_{tpl_id}".format( tpl_id=flow_template_id) with self._db.lock(lock_key): current_instance_num = self._flow_instance_dao.\ query_running_instance_num_by_tpl_id(flow_template_id) if current_instance_num >= flow_template.max_run_instance: raise BadReq( reason="too_many_instance", allow_instance_num=flow_template.max_run_instance) flow_instance = self._flow_instance_dao.insert( flow_template_id, initiator, description) else: flow_instance = self._flow_instance_dao.insert( flow_template_id, initiator, description) # 创建Context ctx = MySQLContext(self, self._db, flow_instance.id) # 回调on_start flow_meta.on_start(ctx, **start_flow_args) # 将状态更新到running self._flow_instance_dao.update_status(flow_instance.id, FlowStatus.STATUS_RUNNING) log.acolyte.info("start flow instance {}".format( to_json(flow_instance))) return Result.ok(data=flow_instance)
def handle_job_action(self, flow_instance_id: int, target_step: str, target_action: str, actor: int, action_args: Dict[str, Any]) -> Result: """处理Job中的Action S1. 检查并获取flow实例 S2. 检查job以及job_action的存在性 S3. 检查执行人是否合法 S4. 检查当前是否可以允许该step及target_action的执行 S5. 合并以及检查相关参数 S6. 回调相关Action逻辑 S7. 返回回调函数的返回值 :param flow_instance_id: flow的标识 :param target_step: 要执行的Step :param target_action: 自定义的动作名称 :param actor: 执行人 :param action_args: 执行该自定义动作所需要的参数 """ if action_args is None: action_args = {} # 检查flow instance的id合法性 flow_instance = self._flow_instance_dao.query_by_instance_id( flow_instance_id) if flow_instance is None: raise BadReq("invalid_flow_instance", flow_instance_id=flow_instance_id) # 检查flow instance的状态 if flow_instance.status != FlowStatus.STATUS_RUNNING: raise BadReq("invalid_status", status=flow_instance.status) # 获取对应的flow template和flow meta flow_template = self._flow_tpl_dao\ .query_flow_template_by_id(flow_instance.flow_template_id) if flow_template is None: raise BadReq("unknown_flow_template", flow_template_id=flow_instance.flow_template_id) try: flow_meta = self._flow_meta_mgr.get(flow_template.flow_meta) except ObjectNotFoundException: raise BadReq("unknown_flow_meta", flow_meta=flow_meta) actor_info = self._user_dao.query_user_by_id(actor) if actor_info is None: raise BadReq("invalid_actor", actor=actor) # 检查当前step以及当前step是否完成 # 检查下一个状态是否是目标状态 handler_mtd, job_def, job_ref = self._check_step( flow_meta, flow_instance, target_step, target_action) # 合并检查参数 request_args - template_bind_args - meta_bind_args rs = self._check_and_combine_action_args(job_def, target_action, action_args, job_ref, flow_template) if rs.status_code == Result.STATUS_BADREQUEST: return rs job_instance = self._job_instance_dao.query_by_instance_id_and_step( instance_id=flow_instance_id, step=target_step) # 如果是trigger事件,需要创建job_instance记录 if target_action == "trigger": job_instance = self._job_instance_dao.insert( flow_instance_id, target_step, actor) self._flow_instance_dao.update_current_step( flow_instance_id, target_step) action_args = rs.data action = self._job_action_dao.insert(job_instance_id=job_instance.id, action=target_action, actor=actor, arguments=action_args, data={}) ctx = MySQLContext(flow_executor=self, db=self._db, flow_instance_id=flow_instance.id, job_instance_id=job_instance.id, job_action_id=action.id, flow_meta=flow_meta, current_step=target_step) rs = handler_mtd(ctx, **action_args) if not isinstance(rs, Result): rs = Result.ok(data=rs) if not rs.is_success(): # 如果返回结果不成功,那么允许重来 self._job_action_dao.delete_by_id(action.id) log.acolyte.info(("Job action executed, " "action_data = {action_data}, " "action_result = {action_result}").format( action_data=to_json(action), action_result=to_json(rs))) return rs
def print_json(self, obj): print(to_json(obj, indent=4 * ' '))
def _func(self, *args, **kwds): rs = func(self, *args, **kwds) self.set_header('Content-Type', 'application/json;charset=utf-8') self.set_status(rs.status_code) self.write(to_json(rs)) self.finish()