会签通常用多实例用户任务表示。一个 BPMN 节点可以产生多条任务,所以“这个节点完成了吗”不能只查询某一个 taskId,也不能把所有历史记录混在一起计数。
首先明确查询范围:哪一个流程实例、哪一个节点、哪一轮会签。流程循环或退回后再次进入同一节点时,节点 ID 不变,但执行轮次已经不同。
按节点查出相关任务
在 Activiti 7.1.0.M6 引擎层,可以按流程实例和节点 ID 查询历史活动。用户任务活动中包含关联的任务 ID:
List<org.activiti.engine.history.HistoricActivityInstance> activities =
historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.activityId(nodeId)
.activityType("userTask")
.list();
for (org.activiti.engine.history.HistoricActivityInstance activity : activities) {
String taskId = activity.getTaskId();
Date endTime = activity.getEndTime();
// 保存每次活动执行的信息;不要仅按 nodeId 去重后判断本轮状态。
}
历史活动查询接口适合需要活动执行信息的情况。如果只需要用户任务,也可以用历史任务查询的 taskDefinitionKey(nodeId):
List<org.activiti.engine.history.HistoricTaskInstance> tasks =
historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.taskDefinitionKey(nodeId)
.list();
这个过滤条件由 TaskInfoQuery 提供。没有必要为了“历史任务不能按节点查”而绕一大圈;应先看所用版本实际支持的查询条件。
单实例:结束时间只说明一次执行结束
对于某次具体的活动执行,endTime 非空可以说明它已结束,但还要区分正常完成、取消或其他结束原因。
如果节点可能重复进入,只要某一条旧记录结束就把整个节点标绿,会掩盖当前正在执行的新任务。查询不到记录,也可能因为历史级别不足或历史已经清理,不能一律标成“未开始”。
多实例:计数器要从正确作用域读取
多实例执行常见的计数变量是:
nrOfInstances:本轮实例总数。nrOfActiveInstances:当前活跃实例数。nrOfCompletedInstances:已完成实例数。
它们属于多实例相关执行作用域。不能任取一个任务的 executionId,再把不存在的变量当成零。下面是已经确定多实例根执行 ID 后的读取片段:
Object total = runtimeService.getVariableLocal(miRootExecutionId, "nrOfInstances");
Object active = runtimeService.getVariableLocal(miRootExecutionId, "nrOfActiveInstances");
Object completed = runtimeService.getVariableLocal(miRootExecutionId, "nrOfCompletedInstances");
if (!(total instanceof Number) || !(active instanceof Number)
|| !(completed instanceof Number)) {
throw new IllegalStateException("多实例计数不可用,先检查执行作用域和生命周期");
}
运行时执行结束后,不应再依赖它的局部变量查询结果。需要长期展示的业务统计,应在适当事件中保存,并与历史记录对照,而不是等执行已删除才读取计数器。
为什么“完成数等于总数”不够
流程可以配置提前完成条件。例如满足一定审批比例后,剩余任务被取消,多实例活动照样结束。这和每个审批人都完成不是同一件事。中断边界事件也可能结束整轮会签。官方多实例概念说明(6.0 用户指南)
因此,页面汇总最好能表达“进行中”“全部正常完成”“因完成条件提前结束”“被取消”和“未知”。“未知”是必要状态:缺历史数据或无法确定轮次时,比显示一个没有依据的“已完成”更准确。
对有循环、退回或并行的流程,先用实例 ID 和执行作用域确定本轮范围,再做状态汇总。相关标识的区别见 任务、节点和历史活动。