一个任务的一辈子

news2024/9/28 5:10:46

总览

  1. 孕育:这一步是生命的起源,对应"任务"就是:申办人因为办理业务而发起一个流程。这是任务产生的摇篮。
    任务的使命就是为了完成业务;
  2. 生产:这是新生命产生的过程,对应"任务"就是:任务的创建和激活。
  3. 长大:婴儿长大了要办满月酒,办周岁,让亲人朋友分享喜悦。对应"任务"就是:通知审批人。
  4. 进入社会:小孩长大了,迟早要进入社会,面对不同人的看法和检阅。对应"任务"就是:给审批人审阅,确认填写资料是否正确,是否合规。
  5. 经受考验:人进入社会之后,会经受各种考验,如果能够成功顶住,就能获取飞跃般的成长。对应"任务"就是:合格合规,得到审批人的认可,不用被打回去重填。
  6. 过关斩将:人在考验中不断成长,日积月累,最终会进入更高一个阶段。 对应"任务"就是:审批人点击【同意】,任务进入下一个阶段。
  7. 死得其所:人一辈子修己,完成自己的使命,最后归于黄土,是一种圆满。 对应"任务"就是:从"RUNNING"状态进入"COMPLETED"状态,光荣完成自己的使命。

名词解释

审批任务

需要人进行审批的任务,以下简称"任务"

任务的状态

/**
     * 非激活任务
     */
    NEW,
    /**
     * 待办任务
     */
    RUNNING,
    /**
     * 暂停任务
     */
    PAUSED,
    /**
     * 取消/撤销
     */
    CANCELED,
    /**
     * 完成
     */
    COMPLETED,
    
    /**
     * 转交
     */
    REDIRECTED

问题:

  1. 转交之后原任务的状态是什么?
    TaskStatus.CANCELED

审批消息

MQ消息类型(此处指业务类型)说明

(只列举部分)

消息种类

说明

备注

PROC_INST_START

流程实例启动(发起流程实例)

TASK_BATCH_ACTIVATED

任务激活

TASK_COMPLETED

任务完成

TASK_CANCEL

任务取消

TASK_REDIRECTED

任务转交

PROCESS_INSTANCE_TERMINATE

流程实例终止(比如申请人撤销)

PROC_INST_FINISH

流程实例完成

PROCESS_INSTANCE_PAUSED

流程实例暂停

生命周期

01 生成流程实例

这是任务产生的摇篮,没有流程实例,就不可能有任务。
流程实例和任务是什么关系呢?一般一个流程实例有多个审批任务
 

什么时候会生成流程实例呢?
一般由业务活动触发
 

比如上图,在采购招投标 的过程中,有很多业务活动,标号(1)到(4)的业务活动都会触发流程实例的生成,即发起审批流。

流程实例生成之后,一定会生成任务吗?
不一定。比如下面的流程,只有一个"自动节点":


不会生成审批任务。

必须要有人工节点(下图标号1-3),才能生成审批任务:


(图01-03)

发起实例流程


(图01-04)
下面是创建流程实例发起的调度项,然后把调度项存储到数据库,再由调度引擎进行一步的调度:

ProcessInstanceStartResumptionExtension extension = new ProcessInstanceStartResumptionExtension(processInstance.getProcessId(), this.getGroupType());
            extension.setParentProcessInstanceId(processInstance.getParentProcessInstanceId());
            extension.setActivityId(activityId);
            ResumptionDO resumption = new ResumptionDO(processInstance.getProcessInstanceId(), extension, processInstance.getAppKey());
            this.flowEngine.asyncStartFlowByResumption(resumption);

asyncStartFlowByResumption 里面做了什么呢?
其实就是把调度项插入到数据库
**this**.resumptionRepositoryManager.insert(resumption, **false**);

 

在调度项处理程序中调用WorkflowRunnerImpl 发起流程

public void startWorkflow(String processInstanceId, long processId) {
        WorkflowContext context = createWorkflowContext(processId, processInstanceId);
        context.getWorkflow().start(context);
    }

会从流程根节点找到第一个节点开始执行,首先找到的肯定是开始节点
 


(图01-05)

执行节点时,根据节点的类型,执行不同的Handler:
 


执行HumanActivityHandler(人工节点handle) 才能生成审批任务

发起流程实例之后,会发送一个变量更新的MQ消息:VariableChangeEvent
 

02 生成新任务

实例发起之后一定会生成任务吗?
只有人工节点才能生成审批任务

生成任务需要哪些准备工作?

  1. 在流程设计的时候,需要为每个人工节点 设置好业务规则(取人规则);
  2. 如果配置了条件节点,那么只有条件节点在运行态满足条件时才能走到审批节点;
  3. 发起实例,即填表(如下图)


(图01-06)

HumanActivityHandler(人工节点) 的执行逻辑

标号1:Activity activity = context.getFlowDefineModel().getActivityById(transition.getDestinationActivityId())
DefaultTransitionRouteHandler.externalExecute
标号2:ElementRuntimeManagerImpl.start
主要是检查前置拦截器,例如人工节点的前置条件
 


com.alibaba.flowengine.ext.workflow.impl.ElementRuntimeManagerImpl#start 中主要是校验前置规则,
实际调用handleBeforeInterceptors
 


其实这是开始节点,因为流程实例启动时,是从开始节点开始执行的.
 


其实目前activity.getActivitySetting().getBeforeInterceptors() 是预留的,还没有使用到
 


基本this.check(elementToStart, context)都会直接返回true

标号3:ElementRuntimeManagerImpl.enter 执行_节点进入后的行为_

标号4:AbstractActivityBehavior.enter
实际会调用BpmActivityBehavior.executeActivity
然后根据activity.getActivitySetting().getIdentifyKey()(HUMAN) 获取到对应的handler,
h获取到HumanActivityHandler
标号5:获取节点实例并执行
BpmsActivityEventBuilder.createActivityStartEvent 的任务:
发送节点实例启动ActivityInstanceStartEvent的 MQ消息
同时执行HumanActivityHandler.perform(activityContext)

标号6:HumanActivityHandler.perform();
 


执行节点实例有两种方式:
(1)同步
(2)异步:先作为调度项ResumptionDO,存储到数据库,然后由调度引擎来异步的执行
 

标号7:_异步调度_;
 


这里要注意的是:此时并没有真正干活,而是把真正要干活的任务存储到了调度项。
下面是异步的方式获取刚才存进去的调度项,然后真正执行:
(调度引擎是如何一步一步来执行调度任务(这里只执行人工节点实例)的)
 

说明
标号1:这里调度引擎开始调度后,真正干活了,所以叫ItemWorker;
 

标号2:completeResumptionSuccessed 方法名称感觉不太好,其实这里是真正干活了,即通过调度项找到具体的handler 去执行;
其中会调用 resumptionHandler.handle(resumption)

标号3:com.alibaba.workflowengine.adapter.resumption.handler.HumanStartResumptionHandler#handle 会做两件事;
(a)通过调度项里面的扩展信息ExtensionContext 获取节点id
 


(b)查询流程版本schema获取该人工节点的配置信息
 

标号4:taskSequenceManager.initAndActivateRootTaskSequenceInternational
是初始化人工节点,并激活;
 

标号5:;
标号6:激活任务序列;
HumanStartResumptionHandler.handle
taskSequenceManager.initAndActivateRootTaskSequenceInternational
 


initAndActivateRootTaskSequenceInternational 具体做了什么呢?
 

03 激活任务

激活任务的时机是什么时候?
一般任务在初始化之后,就会被激活

任务为什么还需要一个激活的动作、多此一举?
比如我收到一个审批任务时,我可能不太肯定,所以前加签给另外一个伙伴,那么我的原来审批任务的状态就变为(PAUSED),等前加签执行完之后,我的审批任务恢复为"激活"状态(RUNNING)

激活任务之后还需要发MQ消息

收到任务激活消息后做了什么处理?

此处是针对消息类型 为TASK_BATCH_ACTIVATED的 消息进行处理:
 


说明
标号1:MQ消费者 监听到消息之后进行处理;
标号2:根据消息种类,转交给具体的handler 进行业务处理;
标号3:根据消息种类,转交给具体的handler 进行业务处理;
标号4:调用 发送审批通知 的逻辑;
标号5:根据"任务激活"消息,获取新激活的任务信息,然后发送审批消息(支持公版钉钉和专有钉钉);
标号6:组装消息卡片,调用钉钉open API 发送工作通知(审批消息);
 

取消任务

04 审批环节

审批人收到任务之后,能做哪些事情?

如果审批人发现自己处理不了应该怎么办?
目前有两种方式:

  1. 转交:把审批任务转交给其他人处理,自己原先的任务就会结束掉
     
  2. 多人填表

审批任务一定需要人工审批吗?
不一定,(see https://bpms.alibaba-inc.com/processdesigner/newProcDesign?processId=15880317601)
如果我们在人工节点 设置了"自动完成规则",那么系统会自动执行(同意或拒绝)该任务

05 审批操作

当审批人点击【同意】、【已处理】或【通过】(按钮名称是可以修改的)时,任务发生了什么变化?
调用接口:executeTask
 

06 任务状态变化

任务的状态机是怎样的?
 

一个任务的状态变化会影响其他任务的状态吗?

07 为什么有任务组

任务组存在的核心目的是 支持审批节点的完成策略
 


上面的人工节点(审批节点) 配置了两个审批人,那么到底怎么样算审批通过呢?
是其中一个人审批通过 就算审批通过(规则1),还是所有审批人都通过才算审批通过(规则2)呢、
这就是完成策略
(以上面为例)实际会生成两个任务,这两个任务输入同一个 任务组(TaskGroup)
比如采用规则1,那么只要有一个人审批通过,那么直接把所在任务组(TaskGroup) 置为“完成",另外一个任务就会自动取消掉。
 

任务模型
任务的taskType为
MIDDLE_IN_ONE_BY_ONE 或 MIDDLE_IN_ALL_AT_ONCE

  • 同时分配(捞单)MIDDLE_IN_ALL_AT_ONCE

  • 逐级审批MIDDLE_IN_ONE_BY_ONE

08 任务完成

审批人点击审批页下面的【同意】、【已处理】或【通过】,如果不出意外,那么任务的状态就变为已完成.
任务完成时会设置额外的流程变量(在自动节点可使用这些流程变量)
see TaskServiceImpl#executeTask(long, String, String, Map<java.lang.String,java.lang.String>, String, String, String, String)
设置的变量如下:

  1. lastTaskActioner : 上一次执行任务的审批人staffId;
  2. lastTaskRemark
  3. lastOutResult
  4. lastTaskId
    其他变量如下:
    内置系统变量
    originator 发起人工号
    originatorLevel 发起人层级
    procInstId 实例ID
    procInstTitle 标题
    procInstTitleEn 英文标题
    processCode 流程编码
    pmc_business_id 业务ID
    ecosCorpId 生态公司
    变量常量见InnerVariableConstants

09 激活下一个任务

执行完当前任务之后,如何激活下一个任务呢?
 


下面从标号14的地方说起:
 


com.alibaba.flowengine.ext.route.handler.impl.MultipleTransitionRouteHandler#externalExecute
 


 

  1. 找到当前节点的出线,
  2. 执行线规则;
  3. 找到出线的startElement,
  4. 按照前面的步骤执行 startElement

执行开始节点

流程实例启动之后,第一个执行的就是开始节点实例
 


也是通过 com.alibaba.flowengine.ext.workflow.impl.ElementRuntimeManagerImpl#start来执行的.
详细步骤:

  1. 开始节点的结构
     
  2. 检查节点的前置规则(目前都为空,这套规则没有用起来),最终调用 handleBeforeInterceptors
  3. 判断能够进入节点,最终调用executeActivity 方法;
  4. 发送MQ事件:ActivityInstanceStartEvent
  5. 调用StartActivityHandler .perform,直接返回true


    其实这里可以考虑用来实现流程发起的白名单机制;
  6. 判断节点此时能够直接离开(完结)--通过com.alibaba.flowengine.ext.workflow.impl.ElementRuntimeManagerImpl#leave;
  7. 实际是校验后置拦截器 ,调用方法handleAfterInterceptors,基本activitySetting.getAfterInterceptors() 都为空(此处没有用起来)
  8. 如果可以离开,则执行this.countReduction,做减数;
  9. 获取路由调度器RouteHandler 进行路由,因为当前节点是开始节点,所以获取到的路由器是线规则路由(MultipleTransitionRouteHandler)
  10. 最终会执行 MultipleTransitionRouteHandler..execute(element, context);
    获取开始节点的出线:
    Set<Transition> outgoingTransitions = activity.getOutTransitions()

  1. 通过检查mei每个出线的线规则,找到符合要求的出线,如果检查出线呢?通过 com.alibaba.flowengine.ext.transition.behavior.AbstractTransitionBehavior#evaluate ,elementRuntimeManager.check
  2. 判断能够进入出线 : this.elementRuntimeManager.enter(transition, context)
  3. 最终执行完路由,找到出线的出口节点transition.getDestinationActivityId(),即下一个人工节点;

  4. 然后又回到执行 com.alibaba.flowengine.ext.workflow.impl.ElementRuntimeManagerImpl#start,
    此处其实是回到了步骤2,又开始下一轮循环

这里应该有一个误区,以为真个过程都是同步的.其实不是的.
上面是开始节点的执行,下面我们开始执行人工节点,其实人工节点的执行就是异步的.

 

人工节点的执行到底干了啥?

  1. 校验 activity.getActivitySetting().getBeforeInterceptors();
  2. 通过 activity.getActivitySetting().getIdentifyKey() 获取到具体的handler来执行,如果是人工节点,那么handler就是HumanActivityHandler;
  3. HumanActivityHandler 在执行过程中也分为异步和同步.如果是异步,则先把执行任务封装成为调度项存储到数据库;
  4. 调度项异步调度执行
  5. 任务完成时会设置额外的流程变量(在自动节点可使用这些流程变量)
    see TaskServiceImpl#executeTask(long, String, String, Map<java.lang.String,java.lang.String>, String, String, String, String)
    设置的变量如下:
  6. lastTaskActioner : 上一次执行任务的审批人staffId;
  7. lastTaskRemark
  8. lastOutResult
  9. lastTaskId

变量常量见InnerVariableConstants

 

自动节点

see HttpServiceRequestHandler,ServerActivityHandler

思考

目前工作流的性能瓶颈在 发起流程实例, 因为大事务,频繁的锁流程实例导致并发能力不够高;
后续会优化的点有以下几点:

  1. 梳理整个流程流转/任务流转的状态机;
  2. 区分哪些是核心信息,哪些是非核心,如果是非核心信息,可以把一致性降低到最终一致性,提高性能;

后续的计划

  1. 流程实例发起白名单,可以通过人工加节点activity.getActivitySetting().getBeforeInterceptors() 来实现
  2. 自动节点能力抽取,复用到更大的业务场景;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2167354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IT运维挑战与对策:构建高效一体化运维管理体系

在当今数字化时代&#xff0c;IT运维作为企业运营的核心支撑&#xff0c;其重要性不言而喻。然而&#xff0c;随着业务规模的扩大和技术的不断革新&#xff0c;IT运维团队面临着前所未有的挑战。本文旨在深度剖析当前IT运维中存在的主要问题&#xff0c;并探索一体化解决方案&a…

1500PLC使用EPOS控制伺服电机

硬件配置与参数 硬件配置 名称 型号 数量 PLC 1512C-1 PN 1个 伺服放大器 V90 PN 1个 伺服电机 SIMOTICS 1个 V90 PN伺服驱动器&#xff1a; 伺服驱动器硬件参数 使用软件&#xff1a;V-ASSISTANT 软件连接时可选择USB连接或者Ethernet连接&#xff0c;根据实际…

【ComfyUI】生成图细节更清晰——Consistency_Decoder

原文&#xff1a;https://github.com/openai/consistencydecoder comfyui: https://github.com/gameltb/Comfyui_Consistency_Decoder_VAE 博文资料下载&#xff1a;https://pan.baidu.com/s/1SwfA4T6iMsA8IrRrGXm4sg?pwd0925 安装 【秋葉aaaki】comfyui一键运行包 夸克网盘…

Vue下载静态文件

1、需求&#xff1a;将静态文件放在本地&#xff0c;让用户进行下载。 2、文件位置&#xff1a; ① 原生js&#xff1a;直接将文件放在某个目录或者根目录下 ② Vue&#xff1a;将文件放在根目录的public文件夹下面 3、代码示例&#xff1a; const url "/模板.xlsx"…

音视频入门基础:AAC专题(9)——FFmpeg源码中计算AAC裸流每个packet的duration和duration_time的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

前言 动手学深度学习课程安排及介绍

前言 动手学深度学习课程安排及介绍 文章目录 前言 动手学深度学习课程安排及介绍课程预告课程安排深度学习介绍 课程预告 学习深度学习关键是动手。 深度学习是人工智能最热的领域核心是神经网络神经网络是一门语言应该像学习Python/C一样学习深度学习 课程安排 【动手学深…

Mysql 存储List类型的数据

python request 爬到的数据里面有一部分是List&#xff0c;一开始在建表时想当然地使用 create table if not exists demo (id TEXT, short_id TEXT, parent_ids LIST)结果报错syntax error&#xff0c;查半天才发现Mysql里没有LIST这个类型 所以存储一个List只能将List数据…

第十六章 模板与泛型编程

16.1 定义模板 模板是C泛型编程的基础。为模板提供足够的信息&#xff0c;就能生成特定的类或函数。 16.1.1 函数模板 在模板定义中&#xff0c;模板参数列表不能为空。 //T的实际类型在编译时根据compare的使用情况来确定 template <typename T> int compare(const …

乱篇弹(54)让子弹飞

创作者在知乎能挣到钱吗&#xff1f; 芝士平台的答案&#xff1a;“当然能&#xff0c;在知乎&#xff0c;无论是各领域的优秀回答者&#xff0c;还是拥有几百或几千关注者的潜力创作者&#xff0c;甚至是只在知乎创作过几篇回答的新人创作者&#xff0c;都有可能在知乎赚钱 。…

[Linux]从零开始的Linux的远程方法介绍与配置教程

一、为什么需要远程Linux 相信大家在学习Linux时&#xff0c;要么是使用Linux的虚拟机或者在物理机上直接安装Linux。这样确实非常方便&#xff0c;我们也能直接看到Linux的桌面或者终端。既然我们都能直接看到终端或者Linux的桌面了&#xff0c;那我们为什么还要远程Linux呢&a…

WebSocket消息防丢ACK和心跳机制对信息安全性的作用及实现方法

WebSocket消息防丢ACK和心跳机制对信息安全性的作用及实现方法 在现代即时通讯&#xff08;IM&#xff09;系统和实时通信应用中&#xff0c;WebSocket作为一种高效的双向通信协议&#xff0c;得到了广泛应用。然而&#xff0c;在实际使用中&#xff0c;如何确保消息的可靠传输…

ai智能抠图有哪些?我只告诉你这些

在广告、设计、摄影以及视频剪辑等创意领域&#xff0c;抠图技术就像是一把神奇的钥匙&#xff0c;能够将图片中的精彩瞬间或独特元素巧妙地分离出来&#xff0c;并融入到全新的背景之中&#xff0c;创造出无限的可能性。 当面对复杂图形的挑战时&#xff0c;使用高效的在线智…

RabbitMQ基础使用

1.MQ基础介绍 同步调用 OpenFeign的调用。这种调用中&#xff0c;调用者发起请求后需要等待服务提供者执行业务返回结果后&#xff0c;才 能继续执行后面的业务。也就是说调用者在调用过程中处于阻塞状态&#xff0c;因此我们称这种调用方式为同步调用 异步调用 异步调用通…

Lucene 倒排索引原理详解:深入探讨相关算法设计

引言 随着互联网的快速发展&#xff0c;数据量呈现爆炸性的增长&#xff0c;如何从海量数据中快速准确地获取所需信息成为了一项挑战。全文搜索引擎的出现极大地解决了这个问题&#xff0c;而 Lucene 正是一款优秀的开源全文搜索引擎库。本文将深入探讨 Lucene 的核心技术之一…

NtripShare测量机器人自动化监测系统测站更换仪器后重新设站

NtripShare测量机器人自动化监测系统投入商业运营已经很久了&#xff0c;在MosBox与自动优化网平差技术的加持下&#xff0c;精度并不让人担心&#xff0c;最近基于客户需求处理了两个比较大的问题。 1、增加对反射片和免棱镜的支持。 2、进一步优化测站更换仪器或重新整平后重…

顶点缓存对象(VBO)与顶点数组对象(VAO)

我们的顶点数组在CPU端的内存里是以数组的形式存在,想要GPU去绘制三角形,那么需要将这些数据传输给GPU。那这些数据在显存端是怎么存储的呢?VBO上场了,它代表GPU上的一段存储空间对象,表现为一个unsigned int类型的变量,GPU端内存对象的一个ID编号、地址、大小。一个VBO对…

Cpp内存管理(7)

文章目录 前言一、C/C内存区域划分二、C/C动态内存管理C语言动态内存管理C动态内存管理对于内置类型对于自定义类型 三、new和delete的底层实现四、new和delete的实现原理五、定位new六、malloc/free和new/delete的区别总结 前言 软件开发过程中&#xff0c;内存管理的重要性不…

vue3中echarts柱状图横轴文字太多放不下怎么解决

问题&#xff1a;在做数据展示的时候&#xff0c;使用的是echarts&#xff0c;遇到了个问题&#xff0c;就是数据过多&#xff0c;但是设置的x轴的文字名称又太长&#xff0c;往往左边第一个或右边最后一个的名称展示不全&#xff0c;只有半个。 从网上找到了几种办法&#xff…

进击J8:Inception v1算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、实验目的&#xff1a; 了解并学习图2中的卷积层运算量的计算过程了解并学习卷积层的并行结构与1x1卷积核部分内容&#xff08;重点&#xff09;尝试根据模…

pdf转换成word有哪些方法?10种将PDF转成word的方法

pdf转换成word有哪些方法&#xff1f;在数字化世界中&#xff0c;PDF和word文档是最常用的两种文件格式。PDF凭借其固定布局和跨平台的兼容性&#xff0c;成为了文件分享的首选&#xff0c;而word则因其灵活的编辑功能被广泛应用于各种文本处理需求。在许多情况下&#xff0c;我…