feat(REQ-4586) - 优化节点计算异常信息的记录

This commit is contained in:
wangli 2025-07-09 15:16:15 +08:00
parent d98ace2792
commit 2306a35afe

View File

@ -1,25 +1,41 @@
package cn.axzo.workflow.core.engine.job;
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
import cn.axzo.workflow.common.model.NextNodePreCheckAlterDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
import cn.axzo.workflow.core.deletage.BpmnTaskAssigneeSelector;
import cn.axzo.workflow.core.listener.Alter;
import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.ReceiveTask;
import org.flowable.bpmn.model.ServiceTask;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.query.QueryProperty;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.Execution;
import org.flowable.job.service.JobHandler;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.variable.api.delegate.VariableScope;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
/**
* TODO
* 检查节点配置是否合法
*
* @author wangli
* @since 2025-07-08 19:44
@ -35,20 +51,121 @@ public class NextActivityConfigCheckJobHandler extends AbstractJobHandler implem
@Override
public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
log.info("NextActivityConfigCheckJobHandler executing...");
log.info("NextActivityConfigCheckJobHandler executing... 当前节点为: {}", job.getJobHandlerConfiguration());
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
FlowNodeForecastService forecastService = SpringContextUtils.getBean(FlowNodeForecastService.class);
List<FlowElement> flowElements = forecastService.performProcessForecasting(job.getProcessInstanceId(), null, job.getJobHandlerConfiguration(), false);
String currentActivityId = job.getJobHandlerConfiguration();
List<FlowElement> flowElements = forecastService.performProcessForecasting(job.getProcessInstanceId(), null, currentActivityId, false);
if (CollectionUtils.isEmpty(flowElements)) {
return;
}
try {
doCheck(job, flowElements, processEngineConfiguration);
} catch (Exception e) {
// 有任何异常则通过钉钉告警
log.warn("NextActivityConfigCheckJobHandler msg: {}", e.getMessage(), e);
Alter alter = SpringContextUtils.getBean(Alter.class);
FlowElement flowElement = ListUtils.emptyIfNull(flowElements).stream().filter(i -> i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask).findFirst().orElse(null);
NextNodePreCheckAlterDTO alterDTO = new NextNodePreCheckAlterDTO();
alterDTO.setProcessInstanceId(job.getProcessInstanceId());
alterDTO.setActivityId(Objects.nonNull(flowElement) ? flowElement.getId() : null);
alterDTO.setErrorMsg(e.getMessage());
alter.invoke(alterDTO);
}
}
private String doCheck(JobEntity job, List<FlowElement> flowElements, ProcessEngineConfigurationImpl processEngineConfiguration) {
AtomicReference<String> checkActivityId = new AtomicReference<>("");
ListUtils.emptyIfNull(flowElements).stream()
.filter(i-> i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)
.forEach(i -> {
.filter(i -> i instanceof UserTask || i instanceof ReceiveTask || i instanceof ServiceTask)
.findFirst().ifPresent(flowElement -> {
log.info("NextActivityConfigCheckJobHandler 计算节点为:{}", flowElement.getId());
getApprovalMethod(flowElement).ifPresent(method -> {
switch (method) {
case autoPassed:
case autoRejection:
case bizSpecify:
break;
default:
List<Execution> executions = processEngineConfiguration.getRuntimeService().createExecutionQuery()
.processInstanceId(job.getProcessInstanceId())
.orderBy((QueryProperty) () -> "START_TIME_").desc().list();
if (CollectionUtils.isEmpty(executions)) {
return;
}
// 这里只会是 human 这一种情况 因为 nobody 在转 BPMN 协议时Activity 直接变成了 ReceiveTask 节点了
List<BpmnTaskDelegateAssigner> assigners = new ArrayList<>();
getApproverSpecify(flowElement).ifPresent(specify -> {
assigners.addAll(approverSelect(specify.getType(), flowElement, (DelegateExecution) executions.get(0), true));
});
// 审批候选人为空时的兜底
emptyAssigneeHandle(assigners, (UserTask) flowElement, (DelegateExecution) executions.get(0));
break;
}
});
checkActivityId.set(flowElement.getId());
});
return checkActivityId.get();
}
public List<BpmnTaskDelegateAssigner> approverSelect(String type, FlowElement flowElement,
DelegateExecution execution,
Boolean throwException) {
List<BpmnTaskAssigneeSelector> selectors = new ArrayList<>(SpringContextUtils.getBeansOfType(BpmnTaskAssigneeSelector.class).values());
List<BpmnTaskDelegateAssigner> assigners = new ArrayList<>();
ListUtils.emptyIfNull(selectors).forEach(select -> {
if (select.support(type)) {
log.info("NextActivityConfigCheckJobHandler-审批任务节点 Id:{}, Name: {}, 审批人指定枚举: {}", flowElement.getId(), flowElement.getName(), type);
List<BpmnTaskDelegateAssigner> selected = select.select(flowElement, execution, throwException);
log.info("NextActivityConfigCheckJobHandler-审批任务节点 Id:{} 的审批人集合为: {}", flowElement.getId(), JSONUtil.toJsonStr(selected));
assigners.addAll(selected);
}
});
return assigners;
}
/**
* 计算节点的待审批人为空时, 执行模型配置中的审批人为空时的处理方式
*
* @param assigners 节点计算的待审批人集合, 可能为空
* @param userTask 当前节点
* @param execution 当前执行实例
*/
private void emptyAssigneeHandle(List<BpmnTaskDelegateAssigner> assigners, UserTask userTask,
DelegateExecution execution) {
// 审批人为空并且当前节点设置了自动跳过条件
if (!CollectionUtils.isEmpty(assigners)) {
return;
}
log.info("NextActivityConfigCheckJobHandler-当前节点id: [{}], name: [{}] 审批人为空, 将执行审批人为空的兜底配置!", userTask.getId(), userTask.getName());
getApproverEmptyHandleType(userTask).ifPresent(type -> {
log.info("NextActivityConfigCheckJobHandler-节点兜底的配置模式:[{}]", type.getType());
switch (type) {
case autoPassed:
case autoRejection:
break;
case transferToAdmin:
try {
assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.transferToAdmin.getType(), userTask,
execution, true));
} catch (Exception e) {
throw new RuntimeException("审批人为空后转交管理员失败, 内部计算信息:" + e.getMessage());
}
break;
case specifyAssignee:
try {
assigners.addAll(approverSelect(ApproverEmptyHandleTypeEnum.specifyAssignee.getType(), userTask,
execution, true));
} catch (Exception e) {
throw new RuntimeException("审批人为空后转交指定人员失败,内部计算信息:" + e.getMessage());
}
break;
default:
break;
}
});
}
}