package com.yunhai.flowcenter.engine; import com.yunhai.flowcenter.entity.FlwDef; import com.yunhai.flowcenter.entity.FlwInstance; import com.yunhai.flowcenter.enums.FlwEnums; import com.yunhai.flowcenter.repository.FlwDefRepository; import com.yunhai.flowcenter.repository.FlwInstanceRepository; import com.yunhai.flowcenter.repository.FlwTaskRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * 节点放行推进(AFTER_COMMIT 监听器经代理调用本 bean,REQUIRES_NEW 生效—— * 事务已提交后的同步监听阶段没有活动事务,@Modifying 批量语句必须有新事务承载): * 该节点待办清零且办件在途才推进;并发冲突由 flw_instance.version 乐观锁暴露,监听器层负责重试。 */ @Slf4j @Service @RequiredArgsConstructor public class FlowAdvanceService { private final FlwInstanceRepository instanceRepository; private final FlwDefRepository defRepository; private final FlwTaskRepository taskRepository; private final FlowEngine flowEngine; /** @return 是否实际推进了 */ @Transactional(propagation = Propagation.REQUIRES_NEW) public boolean tryAdvance(Long instanceId, String nodeId) { FlwInstance instance = instanceRepository.findById(instanceId).orElse(null); if (instance == null || instance.getStatus() != FlwEnums.InstanceStatus.APPROVING.getCode()) { return false; } // 已推进过的节点不再放行(currentNodes 由引擎在放行时移除,乐观锁保证互斥) String current = instance.getCurrentNodes(); boolean active = current != null && java.util.Arrays.stream(current.split(",")) .anyMatch(nodeId::equals); if (!active) { return false; } long pending = taskRepository.findByInstanceIdAndStatus(instanceId, FlwEnums.TaskStatus.PENDING.getCode()).stream() .filter(t -> nodeId.equals(t.getNodeId())) .count(); if (pending > 0) { return false; } FlwDef def = defRepository.findById(instance.getDefId()).orElse(null); if (def == null) { log.error("[flow-center] 办件定义缺失,推进中止:instance={} defId={}", instanceId, instance.getDefId()); return false; } flowEngine.continueAdvance(instance, def, nodeId); instanceRepository.save(instance); return true; } }