From cdc4951924a58c35f65cab563a25ad2d671bbb9c Mon Sep 17 00:00:00 2001 From: jay li Date: Mon, 11 Nov 2024 19:11:37 +0800 Subject: [PATCH] =?UTF-8?q?#IB0SJ1=20=E7=94=9F=E6=88=90=E5=AE=9E=E4=BE=8Bi?= =?UTF-8?q?d=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builder/el/LiteFlowChainELBuilder.java | 40 +++++----- .../DefaultInstanceIdGeneratorSpi.java | 80 +++++++++++++++++++ .../instanceId/InstanceIdGeneratorHolder.java | 43 ++++++++++ .../instanceId/InstanceIdGeneratorSpi.java | 18 +++++ .../liteflow/property/LiteflowConfig.java | 14 ++++ .../instanceId/SqlInstanceIdGeneratorSpi.java | 27 +++++++ ...low.flow.instanceId.InstanceIdGeneratorSpi | 1 + .../instanceIds/InstanceIdELSpringTest.java | 32 ++++++++ 8 files changed, 236 insertions(+), 19 deletions(-) create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultInstanceIdGeneratorSpi.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorHolder.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorSpi.java create mode 100644 liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/spi/instanceId/SqlInstanceIdGeneratorSpi.java create mode 100644 liteflow-rule-plugin/liteflow-rule-sql/src/main/resources/META-INF/services/com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java index 0d759a4f8..52e12ddaa 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java @@ -1,7 +1,6 @@ package com.yomahub.liteflow.builder.el; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.*; import cn.hutool.crypto.digest.MD5; import com.fasterxml.jackson.databind.JsonMappingException; @@ -23,18 +22,16 @@ import com.yomahub.liteflow.flow.element.Executable; import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.flow.element.condition.AndOrCondition; import com.yomahub.liteflow.flow.element.condition.NotCondition; +import com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorHolder; +import com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi; import com.yomahub.liteflow.log.LFLog; import com.yomahub.liteflow.log.LFLoggerManager; import com.yomahub.liteflow.property.LiteflowConfig; import com.yomahub.liteflow.property.LiteflowConfigGetter; -import com.yomahub.liteflow.util.ElRegexUtil; -import java.io.File; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import static com.yomahub.liteflow.common.ChainConstant.NODE_INSTANCE_PATH; -import static com.yomahub.liteflow.common.ChainConstant.USER_DIR; import static com.yomahub.liteflow.util.JsonUtil.*; import static com.yomahub.liteflow.util.SerialsUtil.generateShortUUID; @@ -247,20 +244,24 @@ public class LiteFlowChainELBuilder { } } + // 往condition里设置instanceId private void setNodesInstanceId(Condition condition) { - File nodeDir = new File(System.getProperty(USER_DIR)+ File.separator + NODE_INSTANCE_PATH + File.separator + this.chain.getChainId()); - String elMd5 = MD5.create().digestHex(chain.getEl()); + InstanceIdGeneratorSpi instanceIdGenerator = InstanceIdGeneratorHolder.getInstance().getInstanceIdGenerator(); - // 如果文件不存在,或者文件内容不是当前el,则写入 - if (FileUtil.isEmpty(nodeDir) || !FileUtil.readLines(nodeDir.getPath(), CharsetUtil.UTF_8).get(0).equals(elMd5)) { - writeNodeInstanceId(nodeDir, condition, elMd5); + String elMd5 = MD5.create().digestHex(chain.getEl()); + List instanceIdFile = instanceIdGenerator.readInstanceIdFile(chain.getChainId()); + + // 如果文件不存在,或者文件内容不是当前el,则写入 + if (CollUtil.isEmpty(instanceIdFile) || !instanceIdFile.get(0).equals(elMd5)) { + instanceIdGenerator.writeInstanceIdFile(writeNodeInstanceId(condition, elMd5), chain.getChainId()); } else { // 文件存在,则直接读取 - List nodeList = FileUtil.readLines(nodeDir.getPath(), CharsetUtil.UTF_8); - Map> executableMap = new HashMap<>(); - for (int i = 1; i < nodeList.size(); i++) { - JsonNode groupKeyAndInstanceIds = parseObject(nodeList.get(i)); + for (int i = 1; i < instanceIdFile.size(); i++) { + JsonNode groupKeyAndInstanceIds = parseObject(instanceIdFile.get(i)); + if (groupKeyAndInstanceIds == null) { + continue; + } Iterator fieldNames = groupKeyAndInstanceIds.fieldNames(); while (fieldNames.hasNext()) { @@ -268,8 +269,8 @@ public class LiteFlowChainELBuilder { JsonNode valueNode = groupKeyAndInstanceIds.get(key); if (valueNode.isArray()) { List valueList = new ArrayList<>(); - for (JsonNode item : valueNode) { - valueList.add(item.asText()); + for (int j = 1; j < valueNode.size(); j+=2) { + valueList.add(valueNode.get(j).asText()); } executableMap.put(key, valueList); } @@ -289,8 +290,8 @@ public class LiteFlowChainELBuilder { } } - // 写入时第一行为el的md5,第二行为json格式的groupKey和对应的实例id - private void writeNodeInstanceId(File nodeDir, Condition condition, String elMd5) { + // 写入时第一行为el的md5,第二行为json格式的groupKey和对应的nodeId 和实例id + private List writeNodeInstanceId(Condition condition, String elMd5) { ArrayList writeList = new ArrayList<>(); writeList.add(elMd5); @@ -301,6 +302,7 @@ public class LiteFlowChainELBuilder { executables.forEach(executable -> { if (executable instanceof Node) { ((Node) executable).setInstanceId(generateShortUUID()); + instanceIds.add(executable.getId()); instanceIds.add(((Node) executable).getInstanceId()); } }); @@ -309,7 +311,7 @@ public class LiteFlowChainELBuilder { writeList.add(toJsonString(groupKeyAndInstanceIds)); }); - FileUtil.writeLines(writeList, nodeDir.getPath(), CharsetUtil.UTF_8); + return writeList; } public LiteFlowChainELBuilder setNamespace(String nameSpace){ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultInstanceIdGeneratorSpi.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultInstanceIdGeneratorSpi.java new file mode 100644 index 000000000..93ebc8399 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultInstanceIdGeneratorSpi.java @@ -0,0 +1,80 @@ +package com.yomahub.liteflow.flow.instanceId; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.lang.StringUtils; + +import java.io.File; +import java.util.*; + +import static com.yomahub.liteflow.common.ChainConstant.NODE_INSTANCE_PATH; +import static com.yomahub.liteflow.common.ChainConstant.USER_DIR; +import static com.yomahub.liteflow.util.JsonUtil.parseObject; + +/** + * @author Jay li + */ +public class DefaultInstanceIdGeneratorSpi implements InstanceIdGeneratorSpi { + + private final String basePath = System.getProperty(USER_DIR) + File.separator + NODE_INSTANCE_PATH + File.separator; + + @Override + public List readInstanceIdFile(String chainId) { + if (StringUtils.isBlank(chainId)) { + return Collections.emptyList(); + } + + File nodeDir = new File(basePath + chainId); + if (FileUtil.isEmpty(nodeDir)) { + return Collections.emptyList(); + } + return FileUtil.readLines(nodeDir.getPath(), CharsetUtil.UTF_8); + } + + @Override + public void writeInstanceIdFile(List instanceIdList, String chainId) { + if (StringUtils.isBlank(chainId) || CollUtil.isEmpty(instanceIdList)) { + return; + } + File nodeDir = new File(basePath + chainId); + + FileUtil.writeLines(instanceIdList, nodeDir.getPath(), CharsetUtil.UTF_8); + } + + @Override + public String getNodeInstanceId(String chainId, String instanceId) { + if (StringUtils.isBlank(chainId) || StringUtils.isBlank(instanceId)) { + return ""; + } + + List instanceIdFile = readInstanceIdFile(chainId); + + for (int i = 1; i < instanceIdFile.size(); i++) { + JsonNode groupKeyAndInstanceIds = parseObject(instanceIdFile.get(i)); + + if (groupKeyAndInstanceIds == null) { + continue; + } + + Iterator fieldNames = groupKeyAndInstanceIds.fieldNames(); + while (fieldNames.hasNext()) { + String key = fieldNames.next(); + JsonNode valueNode = groupKeyAndInstanceIds.get(key); + if (valueNode.isArray()) { + Map map = new HashMap<>(); + for (int j = 1; j < valueNode.size(); j+=2) { + String nodeId = valueNode.get(j - 1).asText(); + map.put(nodeId, map.getOrDefault(nodeId, -1)+1); + if (instanceId.equals(valueNode.get(j).asText())) { + return nodeId + "(" + (map.get(nodeId)) + ")"; + } + } + } + } + } + + return ""; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorHolder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorHolder.java new file mode 100644 index 000000000..a456a096d --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorHolder.java @@ -0,0 +1,43 @@ +package com.yomahub.liteflow.flow.instanceId; + +import cn.hutool.core.util.ObjectUtil; + +import java.util.Iterator; +import java.util.ServiceLoader; + +/** + * @author Jay li + */ +public class InstanceIdGeneratorHolder { + private InstanceIdGeneratorSpi instanceIdGenerator; + + private static final InstanceIdGeneratorHolder INSTANCE = new InstanceIdGeneratorHolder(); + + public static void init() { + ServiceLoader loader = ServiceLoader.load(InstanceIdGeneratorSpi.class); + Iterator iterator = loader.iterator(); + if (iterator.hasNext()) { + INSTANCE.setInstanceIdGenerator(iterator.next()); + + } else { + INSTANCE.setInstanceIdGenerator(new DefaultInstanceIdGeneratorSpi()); + } + } + + public static InstanceIdGeneratorHolder getInstance() { + + return INSTANCE; + } + + public InstanceIdGeneratorSpi getInstanceIdGenerator() { + if (ObjectUtil.isNull(instanceIdGenerator)) { + init(); + } + return instanceIdGenerator; + } + + public void setInstanceIdGenerator(InstanceIdGeneratorSpi instanceIdGenerator) { + this.instanceIdGenerator = instanceIdGenerator; + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorSpi.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorSpi.java new file mode 100644 index 000000000..ab6685ea4 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/InstanceIdGeneratorSpi.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.flow.instanceId; + +import java.util.List; + +/** + * @author Jay li + */ +public interface InstanceIdGeneratorSpi { + // 拿文件保存路径, 不同插件不同实现 + // 读取文件内容 核对数据 + List readInstanceIdFile(String chainId); + + // 写入文件保存 + void writeInstanceIdFile(List instanceIdList,String chainId); + + // 根据实例id获取 节点实例定位 + String getNodeInstanceId(String chainId, String instanceId); +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java index 90ba42c5c..2a492eaf6 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java @@ -127,6 +127,9 @@ public class LiteflowConfig { //是否启用节点实例ID private Boolean enableNodeInstanceId; + // instance id 生成器 + private String instanceIdGeneratorClass; + public Boolean getEnableMonitorFile() { return enableMonitorFile; } @@ -524,4 +527,15 @@ public class LiteflowConfig { public void setEnableNodeInstanceId(Boolean enableNodeInstanceId) { this.enableNodeInstanceId = enableNodeInstanceId; } + + public String getInstanceIdGeneratorClass() { + if (StrUtil.isBlank(this.instanceIdGeneratorClass)) { + return "com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator"; + } + return instanceIdGeneratorClass; + } + + public void setInstanceIdGeneratorClass(String instanceIdGeneratorClass) { + this.instanceIdGeneratorClass = instanceIdGeneratorClass; + } } diff --git a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/spi/instanceId/SqlInstanceIdGeneratorSpi.java b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/spi/instanceId/SqlInstanceIdGeneratorSpi.java new file mode 100644 index 000000000..4702d214d --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/spi/instanceId/SqlInstanceIdGeneratorSpi.java @@ -0,0 +1,27 @@ +package com.yomahub.liteflow.parser.spi.instanceId; + +import com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi; + +import java.util.List; + +/** + * sql方式生成instanceId + * @author Jay li + */ + +public class SqlInstanceIdGeneratorSpi implements InstanceIdGeneratorSpi { + @Override + public List readInstanceIdFile(String chainId) { + return null; + } + + @Override + public void writeInstanceIdFile(List instanceIdList, String chainId) { + + } + + @Override + public String getNodeInstanceId(String chainId, String instanceId) { + return ""; + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-sql/src/main/resources/META-INF/services/com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi b/liteflow-rule-plugin/liteflow-rule-sql/src/main/resources/META-INF/services/com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi new file mode 100644 index 000000000..aa433b020 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-sql/src/main/resources/META-INF/services/com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi @@ -0,0 +1 @@ +com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java index 1fbdba597..395b5bf17 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/instanceIds/InstanceIdELSpringTest.java @@ -2,6 +2,8 @@ package com.yomahub.liteflow.test.instanceIds; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorHolder; +import com.yomahub.liteflow.flow.instanceId.InstanceIdGeneratorSpi; import com.yomahub.liteflow.test.BaseTest; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -11,7 +13,9 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -67,6 +71,25 @@ public class InstanceIdELSpringTest extends BaseTest { Assertions.assertEquals(set1, set2); } + + @Test + public void testInstanceIds3() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>a==>a==>a", response.getExecuteStepStr()); + + String executeStepStrWithInstanceId = response.getExecuteStepStrWithInstanceId(); + List strings = extractValuesList(executeStepStrWithInstanceId); + InstanceIdGeneratorSpi instanceIdGenerator = InstanceIdGeneratorHolder.getInstance().getInstanceIdGenerator(); + + for (int i = 0; i < strings.size(); i++) { + Assertions.assertEquals(instanceIdGenerator.getNodeInstanceId("chain2", strings.get(i)), "a(" + i + ")"); + } + + System.out.println(executeStepStrWithInstanceId); + Assertions.assertEquals(strings.size(), 4); + } + public static Set extractValues(String input) { Set values = new HashSet<>(); Pattern pattern = Pattern.compile("\\[(.*?)]"); @@ -77,4 +100,13 @@ public class InstanceIdELSpringTest extends BaseTest { return values; } + public static List extractValuesList(String input) { + List values = new ArrayList<>(); + Pattern pattern = Pattern.compile("\\[(.*?)]"); + Matcher matcher = pattern.matcher(input); + while (matcher.find()) { + values.add(matcher.group(1)); + } + return values; + } }