diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowRetry.java b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowRetry.java index 0c9c182aa..26c7e4032 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowRetry.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowRetry.java @@ -1,7 +1,6 @@ package com.yomahub.liteflow.annotation; import org.springframework.core.annotation.AliasFor; -import org.springframework.stereotype.Component; import java.lang.annotation.*; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java index 02cee03a5..61bf572d2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java @@ -53,6 +53,7 @@ public class ComponentInitializer { } else { LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); nodeComponent.setRetryCount(liteflowConfig.getRetryCount()); + nodeComponent.setNodeExecutorClass(liteflowConfig.getNodeExecutorClass()); } return nodeComponent; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index ec0977f81..506b6db00 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -11,6 +11,8 @@ import cn.hutool.core.date.StopWatch; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.ttl.TransmittableThreadLocal; +import com.yomahub.liteflow.entity.executor.NodeExecutor; +import com.yomahub.liteflow.entity.executor.DefaultNodeExecutor; import com.yomahub.liteflow.enums.NodeTypeEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,13 +23,10 @@ import com.yomahub.liteflow.entity.data.CmpStepType; import com.yomahub.liteflow.entity.data.DataBus; import com.yomahub.liteflow.entity.data.Slot; import com.yomahub.liteflow.entity.flow.Executable; -import com.yomahub.liteflow.entity.flow.Node; import com.yomahub.liteflow.entity.monitor.CompStatistics; -import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.monitor.MonitorBus; import com.yomahub.liteflow.spring.ComponentScanner; -import java.util.HashMap; import java.util.Map; /** @@ -63,6 +62,10 @@ public abstract class NodeComponent{ //在目标异常抛出时才重试 private Class[] retryForExceptions = new Class[]{Exception.class}; + /** 节点执行器的类全名 */ + private String nodeExecutorClass = DefaultNodeExecutor.class.getName(); + + //是否结束整个流程,这个只对串行流程有效,并行流程无效 private final TransmittableThreadLocal isEndTL = new TransmittableThreadLocal<>(); @@ -231,6 +234,14 @@ public abstract class NodeComponent{ this.retryForExceptions = retryForExceptions; } + public String getNodeExecutorClass() { + return nodeExecutorClass; + } + + public void setNodeExecutorClass(String nodeExecutorClass) { + this.nodeExecutorClass = nodeExecutorClass; + } + public void setTag(String tag){ this.tagTL.set(tag); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/DefaultNodeExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/DefaultNodeExecutor.java new file mode 100644 index 000000000..28c64d69c --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/DefaultNodeExecutor.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.entity.executor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.entity.data.DataBus; +import com.yomahub.liteflow.entity.data.Slot; + +/** + * 默认的节点执行器 + * + * @author sikadai + * @date 2022/1/24 17:00 + */ +public class DefaultNodeExecutor extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + Slot slot = DataBus.getSlot(instance.getSlotIndex()); + slot.setData("defaultNodeExecutor", DefaultNodeExecutor.class); + super.execute(instance); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutor.java new file mode 100644 index 000000000..c7b4fc35a --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutor.java @@ -0,0 +1,69 @@ +package com.yomahub.liteflow.entity.executor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.entity.data.DataBus; +import com.yomahub.liteflow.entity.data.Slot; +import com.yomahub.liteflow.exception.ChainEndException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.List; + +/** + * 节点执行器 - 自定的执行策略需要实现该类 + * + * @author sikadai + * @date 2022/1/24 17:00 + */ +public abstract class NodeExecutor { + protected final Logger LOG = LoggerFactory.getLogger(this.getClass()); + + /** + * 执行器执行入口-若需要更大维度的执行方式可以重写该方法 + * + * @param instance : 执行的节点实例 + * @throws Exception + */ + public void execute(NodeComponent instance) throws Exception { + int retryCount = instance.getRetryCount(); + List> forExceptions = Arrays.asList(instance.getRetryForExceptions()); + for (int i = 0; i <= retryCount; i++) { + try { + // 先执行一次 + if (i == 0) { + instance.execute(); + } else { + // 进入重试逻辑 + retry(instance, i); + } + break; + } catch (ChainEndException e) { + //如果是ChainEndException,则无需重试 + throw e; + } catch (Exception e) { + //判断抛出的异常是不是指定异常的子类 + boolean flag = forExceptions.stream().anyMatch(clazz -> clazz.isAssignableFrom(e.getClass())); + //两种情况不重试,1)抛出异常不在指定异常范围内 2)已经重试次数大于等于配置次数 + if (!flag || i >= retryCount) { + throw e; + } + } + } + } + + /** + * 执行重试逻辑 - 子类通过实现该方法进行重试逻辑的控制 + * + * @param instance : 执行的节点实例 + * @param currentRetryCount : 当前重试的次数 + * @throws Exception + */ + + protected void retry(NodeComponent instance, int currentRetryCount) throws Exception { + Slot slot = DataBus.getSlot(instance.getSlotIndex()); + LOG.info("[{}]:component[{}] performs {} retry", slot.getRequestId(), instance.getNodeId(), currentRetryCount + 1); + //执行业务逻辑的主要入口 + instance.execute(); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutorHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutorHelper.java new file mode 100644 index 000000000..f507ed105 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/executor/NodeExecutorHelper.java @@ -0,0 +1,68 @@ +package com.yomahub.liteflow.entity.executor; + +import cn.hutool.core.util.ReflectUtil; +import com.google.common.collect.Maps; +import org.apache.commons.lang.StringUtils; + +import java.util.Map; + +/** + * 节点执行器帮助器 + * + * @author sikadai + * @date 2022/1/24 19:00 + */ +public class NodeExecutorHelper { + /** + * 此处使用Map缓存线程池信息 + * key - 节点执行器类Class全名 + * value - 节点执行器对象 + */ + private final Map nodeExecutorMap; + + private NodeExecutorHelper() { + nodeExecutorMap = Maps.newConcurrentMap(); + } + + /** + * 使用静态内部类实现单例模式 + */ + private static class Holder { + static final NodeExecutorHelper INSTANCE = new NodeExecutorHelper(); + } + + /** + * 获取帮助者的实例 + */ + public static NodeExecutorHelper loadInstance() { + // 外围类能直接访问内部类(不管是否是静态的)的私有变量 + return Holder.INSTANCE; + } + + /** + * 单例模式驱动-通过调用该方法构建节点执行器 + */ + /** + * 单例模式驱动-通过调用该方法构建节点执行器 + * 若nodeExecutorClass为空,则会使用默认的节点执行器 + * + * @param nodeExecutorClass : 节点执行器的Class + * @return + */ + public NodeExecutor buildNodeExecutor(String nodeExecutorClass) { + // 高频操作-采取apache判空操作-效率高于hotool的isBlank将近3倍 + if (StringUtils.isBlank(nodeExecutorClass)) { + // 此处使用默认的节点执行器进行执行 + nodeExecutorClass = DefaultNodeExecutor.class.getName(); + } + NodeExecutor nodeExecutor = nodeExecutorMap.get(nodeExecutorClass); + // 此处无需使用同步锁进行同步-因为即使同时创建了两个实例,但是添加到缓存中的只会存在一个且不会存在并发问题-具体是由ConcurrentMap保证 + if (nodeExecutor == null) { + // 获取重试执行器实例 + nodeExecutor = ReflectUtil.newInstance(nodeExecutorClass); + // 缓存 + nodeExecutorMap.put(nodeExecutorClass, nodeExecutor); + } + return nodeExecutorMap.get(nodeExecutorClass); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java index 1c7e48c99..d0239b2f2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/entity/flow/Node.java @@ -8,9 +8,7 @@ package com.yomahub.liteflow.entity.flow; import java.text.MessageFormat; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import cn.hutool.core.util.ObjectUtil; @@ -18,6 +16,8 @@ import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.entity.data.DataBus; import com.yomahub.liteflow.entity.data.Slot; +import com.yomahub.liteflow.entity.executor.NodeExecutor; +import com.yomahub.liteflow.entity.executor.NodeExecutorHelper; import com.yomahub.liteflow.enums.ExecuteTypeEnum; import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.ChainEndException; @@ -121,31 +121,9 @@ public class Node implements Executable,Cloneable{ //判断是否可执行,所以isAccess经常作为一个组件进入的实际判断要素,用作检查slot里的参数的完备性 if (instance.isAccess()) { //这里开始进行重试的逻辑和主逻辑的运行 - int retryCount = instance.getRetryCount(); - List> forExceptions = Arrays.asList(instance.getRetryForExceptions()); - for (int i = 0; i <= retryCount; i++) { - try { - if (i > 0) { - LOG.info("[{}]:component[{}] performs {} retry", slot.getRequestId(), id, i + 1); - } - //执行业务逻辑的主要入口 - instance.execute(); - break; - } catch (ChainEndException e) { - //如果是ChainEndException,则无需重试 - throw e; - } catch (Exception e) { - //判断抛出的异常是不是指定异常的子类 - boolean flag = forExceptions.stream().anyMatch(clazz -> clazz.isAssignableFrom(e.getClass())); - - //两种情况不重试,1)抛出异常不在指定异常范围内 2)已经重试次数大于等于配置次数 - if (!flag || i >= retryCount) { - throw e; - } - } - } - - + NodeExecutor nodeExecutor = NodeExecutorHelper.loadInstance().buildNodeExecutor(instance.getNodeExecutorClass()); + // 调用节点执行器进行执行 + nodeExecutor.execute(instance); //如果组件覆盖了isEnd方法,或者在在逻辑中主要调用了setEnd(true)的话,流程就会立马结束 if (instance.isEnd()) { String errorInfo = StrUtil.format("[{}]:component[{}] lead the chain to end", slot.getRequestId(), instance.getClass().getSimpleName()); 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 f9873696c..2c6bec487 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 @@ -70,6 +70,8 @@ public class LiteflowConfig { //重试次数 private Integer retryCount; + // 节点执行器的类全名 + private String nodeExecutorClass; //是否打印liteflow banner private Boolean printBanner; @@ -261,4 +263,12 @@ public class LiteflowConfig { public void setThreadExecutorClass(String threadExecutorClass) { this.threadExecutorClass = threadExecutorClass; } + + public String getNodeExecutorClass() { + return nodeExecutorClass; + } + + public void setNodeExecutorClass(String nodeExecutorClass) { + this.nodeExecutorClass = nodeExecutorClass; + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/thread/ExecutorHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/thread/ExecutorHelper.java index 42a518635..8aeafb944 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/thread/ExecutorHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/thread/ExecutorHelper.java @@ -9,7 +9,6 @@ package com.yomahub.liteflow.thread; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.google.common.collect.Maps; import com.yomahub.liteflow.exception.ThreadExecutorServiceCreateException; @@ -31,8 +30,6 @@ public class ExecutorHelper { private final Logger LOG = LoggerFactory.getLogger(ExecutorHelper.class); - private static ExecutorHelper executorHelper; - /** * 此处使用Map缓存线程池信息 * key - 线程池构建者的Class全类名 @@ -44,11 +41,15 @@ public class ExecutorHelper { executorServiceMap = Maps.newConcurrentMap(); } + /** + * 使用静态内部类实现单例模式 + */ + private static class Holder { + static final ExecutorHelper INSTANCE = new ExecutorHelper(); + } + public static ExecutorHelper loadInstance() { - if (ObjectUtil.isNull(executorHelper)) { - executorHelper = new ExecutorHelper(); - } - return executorHelper; + return Holder.INSTANCE; } /** diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java index aa2df2ae6..cbe29d691 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java @@ -47,6 +47,9 @@ public class LiteflowProperty { //是否打印liteflow banner private boolean printBanner; + // 节点执行器class全名 + private String nodeExecutorClass; + public boolean isEnable() { return enable; } @@ -142,4 +145,12 @@ public class LiteflowProperty { public void setThreadExecutorClass(String threadExecutorClass) { this.threadExecutorClass = threadExecutorClass; } + + public String getNodeExecutorClass() { + return nodeExecutorClass; + } + + public void setNodeExecutorClass(String nodeExecutorClass) { + this.nodeExecutorClass = nodeExecutorClass; + } } diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java index f242ed0bf..8ea46e836 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java @@ -41,6 +41,7 @@ public class LiteflowPropertyAutoConfiguration { liteflowConfig.setRetryCount(property.getRetryCount()); liteflowConfig.setZkNode(property.getZkNode()); liteflowConfig.setPrintBanner(property.isPrintBanner()); + liteflowConfig.setNodeExecutorClass(property.getNodeExecutorClass()); return liteflowConfig; } } diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java index 218944e5d..d744c69be 100644 --- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java @@ -7,7 +7,6 @@ import com.yomahub.liteflow.test.BaseTest; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; @@ -18,7 +17,7 @@ import javax.annotation.Resource; /** - * 测试springboot下的组件重试 + * 测试springboot下的节点执行器 * @author Bryan.Zhang * @since 2.5.10 */ diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java new file mode 100644 index 000000000..b82724608 --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutor.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.entity.data.DataBus; +import com.yomahub.liteflow.entity.data.Slot; +import com.yomahub.liteflow.entity.executor.NodeExecutor; + +import java.util.concurrent.TimeUnit; + +/** + * 自定义节点执行器 + */ +public class CustomerNodeExecutor extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + Slot slot = DataBus.getSlot(instance.getSlotIndex()); + LOG.info("使用customerNodeExecutor进行执行"); + slot.setData("customerNodeExecutor", this.getClass()); + super.execute(instance); + } + +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java new file mode 100644 index 000000000..46792852a --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/CustomerNodeExecutorAndCustomRetry.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.entity.data.DataBus; +import com.yomahub.liteflow.entity.data.Slot; +import com.yomahub.liteflow.entity.executor.NodeExecutor; + +import java.util.concurrent.TimeUnit; + +/** + * 自定义节点执行器 + */ +public class CustomerNodeExecutorAndCustomRetry extends NodeExecutor { + @Override + public void execute(NodeComponent instance) throws Exception { + Slot slot = DataBus.getSlot(instance.getSlotIndex()); + LOG.info("使用customerNodeExecutorAndCustomRetry进行执行"); + slot.setData("customerNodeExecutorAndCustomRetry", this.getClass()); + super.execute(instance); + } + + @Override + protected void retry(NodeComponent instance, int currentRetryCount) throws Exception { + TimeUnit.MICROSECONDS.sleep(20L); + Slot slot = DataBus.getSlot(instance.getSlotIndex()); + slot.setData("retryLogic", this.getClass()); + super.retry(instance, currentRetryCount); + } +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorSpringbootTest.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorSpringbootTest.java new file mode 100644 index 000000000..b83bcb518 --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/LiteflowNodeExecutorSpringbootTest.java @@ -0,0 +1,70 @@ +package com.yomahub.liteflow.test.nodeExecutor; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.entity.data.DefaultSlot; +import com.yomahub.liteflow.entity.data.LiteflowResponse; +import com.yomahub.liteflow.entity.executor.DefaultNodeExecutor; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + + +/** + * 测试springboot下的组件重试 + * + * @author Bryan.Zhang + * @since 2.5.10 + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/nodeExecutor/application.properties") +@SpringBootTest(classes = LiteflowNodeExecutorSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.nodeExecutor.cmp"}) +public class LiteflowNodeExecutorSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + // 默认执行器测试 + @Test + public void testDefaultExecutor() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(DefaultNodeExecutor.class, response.getSlot().getData("defaultNodeExecutor")); + Assert.assertEquals("a", response.getSlot().getExecuteStepStr()); + } + + //默认执行器测试+全局重试配置测试 + @Test + public void testDefaultExecutorForRetry() { + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(DefaultNodeExecutor.class, response.getSlot().getData("defaultNodeExecutor")); + Assert.assertEquals("b==>b==>b", response.getSlot().getExecuteStepStr()); + } + + //自定义执行器测试 + @Test + public void testCustomerExecutor() { + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("c", response.getSlot().getExecuteStepStr()); + } + + //自定义执行器测试+全局重试配置测试 + @Test + public void testCustomExecutorForRetry() { + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertFalse(response.isSuccess()); + Assert.assertEquals(CustomerNodeExecutorAndCustomRetry.class, response.getSlot().getData("retryLogic")); + Assert.assertEquals("d==>d==>d==>d==>d==>d", response.getSlot().getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java new file mode 100644 index 000000000..8fd765bb1 --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/ACmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * + * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } + +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java new file mode 100644 index 000000000..6e737879e --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/BCmp.java @@ -0,0 +1,27 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent("b") +public class BCmp extends NodeComponent { + + private int flag = 0; + + @Override + public void process() { + System.out.println("BCmp executed!"); + if (flag < 2){ + flag++; + throw new RuntimeException("demo exception"); + } + } + +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java new file mode 100644 index 000000000..6762d18ad --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/CCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.nodeExecutor.CustomerNodeExecutor; + +@LiteflowComponent("c") +@LiteflowRetry(5) +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + + @Override + public String getNodeExecutorClass() { + return CustomerNodeExecutor.class.getName(); + } +} diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java new file mode 100644 index 000000000..d60135a03 --- /dev/null +++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/nodeExecutor/cmp/DCmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.nodeExecutor.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowRetry; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.test.nodeExecutor.CustomerNodeExecutor; +import com.yomahub.liteflow.test.nodeExecutor.CustomerNodeExecutorAndCustomRetry; + +@LiteflowComponent("d") +@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class}) +public class DCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("DCmp executed!"); + throw new NullPointerException("demo exception"); + } + + @Override + public String getNodeExecutorClass() { + return CustomerNodeExecutorAndCustomRetry.class.getName(); + } +} diff --git a/liteflow-testcase-springboot/src/test/resources/nodeExecutor/application.properties b/liteflow-testcase-springboot/src/test/resources/nodeExecutor/application.properties new file mode 100644 index 000000000..07f53dddf --- /dev/null +++ b/liteflow-testcase-springboot/src/test/resources/nodeExecutor/application.properties @@ -0,0 +1,4 @@ +liteflow.rule-source=nodeExecutor/flow.xml +liteflow.retry-count=3 +liteflow.slot-size=512 +liteflow.node-executor=com.yomahub.liteflow.entity.executor.DefaultNodeExecutor \ No newline at end of file diff --git a/liteflow-testcase-springboot/src/test/resources/nodeExecutor/flow.xml b/liteflow-testcase-springboot/src/test/resources/nodeExecutor/flow.xml new file mode 100644 index 000000000..6b867c5bc --- /dev/null +++ b/liteflow-testcase-springboot/src/test/resources/nodeExecutor/flow.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file