示例#1
0
 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()
示例#2
0
    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
示例#5
0
 def print_json(self, obj):
     print(to_json(obj, indent=4 * ' '))
示例#6
0
 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()