diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/constants/WorkFlowConstants.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/constants/WorkFlowConstants.java new file mode 100644 index 00000000..ef862260 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/constants/WorkFlowConstants.java @@ -0,0 +1,11 @@ +package com.qqchen.deploy.backend.workflow.constants; + +public interface WorkFlowConstants { + + public static final String WORKFLOW_EXEC_ERROR = "WORKFLOW_EXEC_ERROR"; + + public static final String BOUNDARY_EVENT_ERROR_PREFIX = "BOUNDARY_EVENT_ERROR_"; + public static final String END_EVENT_ERROR_PREFIX = "END_EVENT_ERROR_"; + public static final String SEQUENCE_FLOW_ERROR_PREFIX = "SEQUENCE_FLOW_ERROR_"; + +} diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java index 52d89988..9827b732 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/delegate/ShellTaskDelegate.java @@ -1,11 +1,13 @@ package com.qqchen.deploy.backend.workflow.delegate; +import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants; import com.qqchen.deploy.backend.workflow.event.ShellLogEvent; import com.qqchen.deploy.backend.workflow.enums.NodeLogTypeEnums; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.FlowableException; import org.flowable.engine.RuntimeService; import org.flowable.engine.ManagementService; +import org.flowable.engine.delegate.BpmnError; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.JavaDelegate; import org.flowable.common.engine.api.delegate.Expression; @@ -78,8 +80,7 @@ public class ShellTaskDelegate implements JavaDelegate { if (scriptValue == null) { log.error("脚本内容为空,执行失败"); - handleFailure(execution, "Script is required but not provided"); - return; + throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Script is required but not provided"); } try { @@ -169,8 +170,7 @@ public class ShellTaskDelegate implements JavaDelegate { if (exitCode != 0) { log.error("Shell脚本执行失败,退出码: {}", exitCode); log.error("错误输出: {}", finalError); - handleFailure(execution, "Shell脚本执行失败,退出码: " + exitCode); - return; + throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败,退出码: " + exitCode); } log.info("Shell脚本执行成功"); @@ -178,14 +178,7 @@ public class ShellTaskDelegate implements JavaDelegate { } catch (Exception e) { log.error("Shell脚本执行失败", e); -// Job job = managementService.createJobQuery() -// .processInstanceId(execution.getProcessInstanceId()) -// .singleResult(); -// if (job != null) { -// // 设置重试次数为 0,这样就不会进入死信队列 -// managementService.setJobRetries(job.getId(), 0); -// } - throw new FlowableException("脚本执行失败。"); + throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败"); } } @@ -217,25 +210,4 @@ public class ShellTaskDelegate implements JavaDelegate { } - private void handleFailure(DelegateExecution execution, String errorMessage) { - String processInstanceId = execution.getProcessInstanceId(); - - // 获取当前 Job - Job job = managementService.createJobQuery() - .processInstanceId(execution.getProcessInstanceId()) - .singleResult(); - if (job != null) { - // 设置重试次数为 0,这样就不会进入死信队列 - managementService.setJobRetries(job.getId(), 0); - } - throw new FlowableException(errorMessage); - -// try { - // 直接终止流程实例 -// runtimeService.deleteProcessInstance(processInstanceId, errorMessage); - -// } catch (Exception e) { -// log.error("处理Shell任务失败时出现错误,流程实例: {}", processInstanceId, e); -// } - } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java index 89205780..6bcde15a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java @@ -26,7 +26,7 @@ public class ActivityEventHandler implements IFlowableEventHandler { @Override public void handle(FlowableEvent event) { String eventType = event.getType().name(); - log.info("Processing activity event: {}", eventType); +// log.info("Processing activity event: {}", eventType); if (!(event instanceof FlowableActivityEvent activityEvent)) { return; @@ -35,17 +35,17 @@ public class ActivityEventHandler implements IFlowableEventHandler { WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType); if (status != null) { - publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() - .processInstanceId(activityEvent.getProcessInstanceId()) - .executionId(activityEvent.getExecutionId()) - .nodeId(activityEvent.getActivityId()) - .nodeName(activityEvent.getActivityName()) - .nodeType(activityEvent.getActivityType()) - .status(status) - .startTime(status == WorkflowNodeInstanceStatusEnums.RUNNING ? LocalDateTime.now() : null) - .endTime(status.isFinalState() ? LocalDateTime.now() : null) - .build() - ); +// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() +// .processInstanceId(activityEvent.getProcessInstanceId()) +// .executionId(activityEvent.getExecutionId()) +// .nodeId(activityEvent.getActivityId()) +// .nodeName(activityEvent.getActivityName()) +// .nodeType(activityEvent.getActivityType()) +// .status(status) +// .startTime(status == WorkflowNodeInstanceStatusEnums.RUNNING ? LocalDateTime.now() : null) +// .endTime(status.isFinalState() ? LocalDateTime.now() : null) +// .build() +// ); } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java index e94fbdfb..c7bdb3e0 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java @@ -28,29 +28,29 @@ public class JobEventHandler implements IFlowableEventHandler { @Override public void handle(FlowableEvent event) { String eventType = event.getType().name(); - log.info("Processing job event: {}", eventType); +// log.info("Processing job event: {}", eventType); if (!(event instanceof FlowableEngineEntityEvent entityEvent)) { return; } - log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType()); +// log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType()); JobEntityImpl job = (JobEntityImpl) entityEvent.getEntity(); WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType); if (status != null) { - publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() - .processInstanceId(job.getProcessInstanceId()) - .executionId(job.getExecutionId()) - .nodeId(job.getElementId()) - .nodeName(job.getElementName()) - .nodeType(job.getJobHandlerType()) - .status(status) - .startTime(job.getCreateTime() != null ? DateUtil.toLocalDateTime(job.getCreateTime()) : null) - .endTime(status.isFinalState() ? LocalDateTime.now() : null) - .build() - ); +// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() +// .processInstanceId(job.getProcessInstanceId()) +// .executionId(job.getExecutionId()) +// .nodeId(job.getElementId()) +// .nodeName(job.getElementName()) +// .nodeType(job.getJobHandlerType()) +// .status(status) +// .startTime(job.getCreateTime() != null ? DateUtil.toLocalDateTime(job.getCreateTime()) : null) +// .endTime(status.isFinalState() ? LocalDateTime.now() : null) +// .build() +// ); } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java index a23ff7ab..92b147fb 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java @@ -33,24 +33,24 @@ public class ProcessEventHandler implements IFlowableEventHandler { @Override public void handle(FlowableEvent event) { String eventType = event.getType().name(); - log.info("Processing event: {}", eventType); +// log.info("Processing event: {}", eventType); FlowableProcessEngineEvent processEvent = (FlowableProcessEngineEvent) event; WorkflowInstanceStatusEnums status = convertToWorkflowStatus(eventType); if (status != null) { - HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService() - .createHistoricProcessInstanceQuery() - .processInstanceId(processEvent.getProcessInstanceId()) - .singleResult(); - - publisher.publishEvent(WorkflowInstanceStatusChangeEvent.builder() - .processInstanceId(processEvent.getProcessInstanceId()) - .status(status) - .endTime(historicProcessInstance != null && historicProcessInstance.getEndTime() != null ? - DateUtil.toLocalDateTime(historicProcessInstance.getEndTime()) : null) - .build() - ); +// HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService() +// .createHistoricProcessInstanceQuery() +// .processInstanceId(processEvent.getProcessInstanceId()) +// .singleResult(); +// +// publisher.publishEvent(WorkflowInstanceStatusChangeEvent.builder() +// .processInstanceId(processEvent.getProcessInstanceId()) +// .status(status) +// .endTime(historicProcessInstance != null && historicProcessInstance.getEndTime() != null ? +// DateUtil.toLocalDateTime(historicProcessInstance.getEndTime()) : null) +// .build() +// ); } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java index b7edce33..de817d8a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java @@ -1,5 +1,6 @@ package com.qqchen.deploy.backend.workflow.util; +import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants; import com.qqchen.deploy.backend.workflow.dto.graph.*; import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums; import lombok.extern.slf4j.Slf4j; @@ -38,6 +39,8 @@ public class BpmnConverter { // 创建BPMN模型 BpmnModel bpmnModel = new BpmnModel(); + bpmnModel.setTargetNamespace("http://www.flowable.org/test"); + Process process = new Process(); // 确保processKey符合NCName规则 String validProcessKey = processKey.replaceAll("[^a-zA-Z0-9-_.]", "_"); @@ -67,7 +70,7 @@ public class BpmnConverter { element.setName(node.getName()); // 设置节点特定属性 - configureFlowElement(element, node); + configureFlowElement(element, node, process); process.addFlowElement(element); } @@ -109,8 +112,9 @@ public class BpmnConverter { * 配置流程节点的特定属性 * @param element 流程节点元素 * @param node 工作流节点定义 + * @param process 当前流程 */ - private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node) { + private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node, Process process) { if (element instanceof ServiceTask) { ServiceTask serviceTask = (ServiceTask) element; // 设置委托表达式 @@ -126,42 +130,57 @@ public class BpmnConverter { failedJobRetryTimeCycle.setNamespacePrefix("flowable"); failedJobRetryTimeCycle.setElementText("R0/PT1H"); // 设置为0次重试 - // 添加错误处理配置 - ExtensionElement errorHandling = new ExtensionElement(); - errorHandling.setName("failOnError"); - errorHandling.setNamespace("http://flowable.org/bpmn"); - errorHandling.setNamespacePrefix("flowable"); - errorHandling.setElementText("true"); - Map> extensionElements = new HashMap<>(); List retryElements = new ArrayList<>(); retryElements.add(failedJobRetryTimeCycle); extensionElements.put("failedJobRetryTimeCycle", retryElements); - List errorElements = new ArrayList<>(); - errorElements.add(errorHandling); - extensionElements.put("failOnError", errorElements); - + // 添加字段注入 + List fieldExtensions = new ArrayList<>(); + node.getConfig().forEach((key, value) -> { + if (value != null && !"delegate".equals(key)) { + FieldExtension fieldExtension = new FieldExtension(); + fieldExtension.setFieldName(key); + fieldExtension.setStringValue(String.valueOf(value)); + fieldExtensions.add(fieldExtension); + } + }); + serviceTask.setFieldExtensions(fieldExtensions); serviceTask.setExtensionElements(extensionElements); - } - // 后续可以添加其他类型的节点配置 - // else if (element instanceof UserTask) { ... } - } + + // 添加错误边界事件 + BoundaryEvent boundaryEvent = new BoundaryEvent(); + boundaryEvent.setId("error_boundary_" + serviceTask.getId()); + boundaryEvent.setName("错误边界事件"); + boundaryEvent.setAttachedToRef(serviceTask); + boundaryEvent.setAttachedToRefId(serviceTask.getId()); + boundaryEvent.setCancelActivity(true); // 确保取消原有活动 + + // 配置错误事件定义 + ErrorEventDefinition errorEventDefinition = new ErrorEventDefinition(); + errorEventDefinition.setErrorCode(WorkFlowConstants.WORKFLOW_EXEC_ERROR); + boundaryEvent.addEventDefinition(errorEventDefinition); + + // 添加错误结束事件 + EndEvent errorEndEvent = new EndEvent(); + errorEndEvent.setId("error_end_" + serviceTask.getId()); + errorEndEvent.setName("错误结束事件"); - /** - * 添加扩展属性 - */ - private void addExtensionElement(Map> extensionElements, String name, String value) { - if (value != null && !value.trim().isEmpty()) { - ExtensionElement extensionElement = new ExtensionElement(); - extensionElement.setName(name); - extensionElement.setNamespace("http://flowable.org/bpmn"); - extensionElement.setNamespacePrefix("flowable"); + // 添加终止定义 + TerminateEventDefinition terminateEventDefinition = new TerminateEventDefinition(); + errorEndEvent.addEventDefinition(terminateEventDefinition); - // 直接设置文本值,让Flowable自己处理XML转义 - extensionElement.setElementText(value); + // 添加从边界事件到结束事件的连线 + SequenceFlow errorFlow = new SequenceFlow(); + errorFlow.setId("error_flow_" + serviceTask.getId()); + errorFlow.setName("错误处理流程"); + errorFlow.setSourceRef(boundaryEvent.getId()); + errorFlow.setTargetRef(errorEndEvent.getId()); - extensionElements.computeIfAbsent(name, k -> new ArrayList<>()).add(extensionElement); + // 将错误处理相关的元素添加到流程中 + process.addFlowElement(boundaryEvent); + process.addFlowElement(errorEndEvent); + process.addFlowElement(errorFlow); } } }