mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 20:22:07 +08:00
!192 feature #I7I3LL 增加maxWaitSeconds关键字,允许对EL中的每一个组件进行超时控制
Merge pull request !192 from DaleLee/dev-timeout
This commit is contained in:
@@ -78,6 +78,7 @@ public class LiteFlowChainELBuilder {
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PARALLEL, Object.class, new ParallelOperator());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* EL 规则中的 maxWaitSeconds 的操作符
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public class MaxWaitSecondsOperator extends BaseOperator<Condition> {
|
||||
@Override
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
Executable executable = OperatorHelper.convert(objects[0], Executable.class);
|
||||
// 获取传入的时间参数
|
||||
Integer maxWaitSeconds = OperatorHelper.convert(objects[1], Integer.class);
|
||||
if (executable instanceof WhenCondition) {
|
||||
// WhenCondition,直接设置等待时间
|
||||
WhenCondition whenCondition = OperatorHelper.convert(executable, WhenCondition.class);
|
||||
whenCondition.setMaxWaitTime(maxWaitSeconds);
|
||||
whenCondition.setMaxWaitTimeUnit(TimeUnit.SECONDS);
|
||||
return whenCondition;
|
||||
} else if (executable instanceof FinallyCondition) {
|
||||
// FINALLY,报错
|
||||
String errorMsg = StrFormatter.format("The caller [{}] cannot use the keyword \"maxWaitSeconds'\"", executable.toString());
|
||||
throw new QLException(errorMsg);
|
||||
} else if (containsFinally(executable)) {
|
||||
// 处理 THEN 中的 FINALLY
|
||||
ThenCondition thenCondition = OperatorHelper.convert(executable, ThenCondition.class);
|
||||
return handleFinally(thenCondition, maxWaitSeconds);
|
||||
} else {
|
||||
// 其他情况,被 WHEN 包装
|
||||
return wrappedByTimeout(executable, maxWaitSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个 Executable 包装为带有单独超时控制的 TimeoutCondition
|
||||
*
|
||||
* @param executable 待包装对象
|
||||
* @param maxWaitSeconds 最大等待秒数
|
||||
* @return 包装后的 TimeoutCondition
|
||||
*/
|
||||
private TimeoutCondition wrappedByTimeout(Executable executable, Integer maxWaitSeconds) {
|
||||
TimeoutCondition timeoutCondition = new TimeoutCondition();
|
||||
timeoutCondition.addExecutable(executable);
|
||||
timeoutCondition.setMaxWaitTime(maxWaitSeconds);
|
||||
timeoutCondition.setMaxWaitTimeUnit(TimeUnit.SECONDS);
|
||||
return timeoutCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 THEN 中是否含有 FINALLY 组件
|
||||
*
|
||||
* @param executable 判断对象
|
||||
* @return 含有 FINALLY 组件返回 true,否则返回 false
|
||||
*/
|
||||
private boolean containsFinally(Executable executable) {
|
||||
return executable instanceof ThenCondition
|
||||
&& CollUtil.isNotEmpty(((ThenCondition) executable).getFinallyConditionList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 FINALLY 排除在超时控制之外
|
||||
*
|
||||
* @param thenCondition 待处理的 ThenCondition
|
||||
* @param maxWaitSeconds 最大等待秒数
|
||||
* @return 处理后的 ThenCondition
|
||||
*/
|
||||
private ThenCondition handleFinally(ThenCondition thenCondition, Integer maxWaitSeconds) {
|
||||
// 进行如下转换
|
||||
// THEN(PRE(a),b,FINALLY(c))
|
||||
// => THEN(
|
||||
// WHEN(THEN(PRE(a),b)),
|
||||
// FINALLY(c))
|
||||
|
||||
// 定义外层 THEN
|
||||
ThenCondition outerThenCondition = new ThenCondition();
|
||||
|
||||
// 把 FINALLY 转移到外层 THEN
|
||||
List<Executable> finallyList = thenCondition.getExecutableList(ConditionKey.FINALLY_KEY);
|
||||
finallyList.forEach(executable
|
||||
-> outerThenCondition
|
||||
.addFinallyCondition((FinallyCondition) executable));
|
||||
finallyList.clear();
|
||||
|
||||
// 包装内部 THEN
|
||||
WhenCondition whenCondition = wrappedByTimeout(thenCondition, maxWaitSeconds);
|
||||
outerThenCondition.addExecutable(whenCondition);
|
||||
|
||||
return outerThenCondition;
|
||||
}
|
||||
}
|
||||
@@ -82,4 +82,6 @@ public interface ChainConstant {
|
||||
|
||||
String NOT = "NOT";
|
||||
|
||||
String MAX_WAIT_SECONDS = "maxWaitSeconds";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* 超时控制 Condition
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public class TimeoutCondition extends WhenCondition {
|
||||
|
||||
@Override
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
try {
|
||||
super.executeCondition(slotIndex);
|
||||
} catch (WhenTimeoutException ex) {
|
||||
// 将 WhenTimeoutException 转换为 TimeoutException
|
||||
String errMsg = StrFormatter.format("Timed out when executing the chain [{}] because [{}] exceeded {} {}.",
|
||||
this.getCurrChainId(), this.getCurrentExecutableId(), this.getMaxWaitTime(), this.getMaxWaitTimeUnit().toString().toLowerCase());
|
||||
throw new TimeoutException(errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前组件的 id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getCurrentExecutableId() {
|
||||
// TimeoutCondition 只有一个 Executable
|
||||
Executable executable = this.getExecutableList().get(0);
|
||||
if (ObjectUtil.isNotNull(executable.getId())) {
|
||||
// 已经有 id 了
|
||||
return executable.getId();
|
||||
}
|
||||
// 定义 id
|
||||
switch (executable.getExecuteType()) {
|
||||
// chain 和 node 一般都有 id
|
||||
case CHAIN:
|
||||
return ((Chain) executable).getChainId();
|
||||
case CONDITION:
|
||||
return "condition-" + ((Condition) executable).getConditionType().getName();
|
||||
case NODE:
|
||||
return "node-" + ((Node) executable).getType().getCode();
|
||||
default:
|
||||
return "unknown-executable";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,12 @@ public class WhenCondition extends Condition {
|
||||
// when单独的线程池名称
|
||||
private String threadExecutorClass;
|
||||
|
||||
// 异步线程最⻓的等待时间
|
||||
private Integer maxWaitTime;
|
||||
|
||||
// 等待时间单位
|
||||
private TimeUnit maxWaitTimeUnit;
|
||||
|
||||
@Override
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
executeAsyncCondition(slotIndex);
|
||||
@@ -86,15 +92,20 @@ public class WhenCondition extends Condition {
|
||||
// 3.根据condition.getNodeList()的集合进行流处理,用map进行把executable对象转换成List<CompletableFuture<WhenFutureObj>>
|
||||
// 4.在转的过程中,套入CompletableFutureTimeout方法进行超时判断,如果超时则用WhenFutureObj.timeOut返回超时的对象
|
||||
// 5.第2个参数是主要的本体CompletableFuture,传入了ParallelSupplier和线程池对象
|
||||
Integer whenMaxWaitTime;
|
||||
TimeUnit whenMaxWaitTimeUnit;
|
||||
if (ObjectUtil.isNull(this.getMaxWaitTime())) {
|
||||
if (ObjectUtil.isNotNull(liteflowConfig.getWhenMaxWaitSeconds())) {
|
||||
// 获取全局异步线程最长等待秒数
|
||||
this.setMaxWaitTime(liteflowConfig.getWhenMaxWaitSeconds());
|
||||
this.setMaxWaitTimeUnit(TimeUnit.SECONDS);
|
||||
} else {
|
||||
// 获取全局异步线程最⻓的等待时间
|
||||
this.setMaxWaitTime(liteflowConfig.getWhenMaxWaitTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotNull(liteflowConfig.getWhenMaxWaitSeconds())){
|
||||
whenMaxWaitTime = liteflowConfig.getWhenMaxWaitSeconds();
|
||||
whenMaxWaitTimeUnit = TimeUnit.SECONDS;
|
||||
}else{
|
||||
whenMaxWaitTime = liteflowConfig.getWhenMaxWaitTime();
|
||||
whenMaxWaitTimeUnit = liteflowConfig.getWhenMaxWaitTimeUnit();
|
||||
if (ObjectUtil.isNull(this.getMaxWaitTimeUnit())) {
|
||||
// 获取全局异步线程最⻓的等待时间单位
|
||||
this.setMaxWaitTimeUnit(liteflowConfig.getWhenMaxWaitTimeUnit());
|
||||
}
|
||||
|
||||
List<CompletableFuture<WhenFutureObj>> completableFutureList = this.getExecutableList()
|
||||
@@ -112,7 +123,7 @@ public class WhenCondition extends Condition {
|
||||
WhenFutureObj.timeOut(executable.getId()),
|
||||
CompletableFuture.supplyAsync(new ParallelSupplier(executable, currChainName, slotIndex),
|
||||
parallelExecutor),
|
||||
whenMaxWaitTime, whenMaxWaitTimeUnit))
|
||||
this.getMaxWaitTime(), this.getMaxWaitTimeUnit()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
CompletableFuture<?> resultCompletableFuture;
|
||||
@@ -221,4 +232,19 @@ public class WhenCondition extends Condition {
|
||||
this.threadExecutorClass = threadExecutorClass;
|
||||
}
|
||||
|
||||
public Integer getMaxWaitTime() {
|
||||
return maxWaitTime;
|
||||
}
|
||||
|
||||
public void setMaxWaitTime(Integer maxWaitTime) {
|
||||
this.maxWaitTime = maxWaitTime;
|
||||
}
|
||||
|
||||
public TimeUnit getMaxWaitTimeUnit() {
|
||||
return maxWaitTimeUnit;
|
||||
}
|
||||
|
||||
public void setMaxWaitTimeUnit(TimeUnit maxWaitTimeUnit) {
|
||||
this.maxWaitTimeUnit = maxWaitTimeUnit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class LiteFlowDefaultWhenExecutorBuilder implements ExecutorBuilder {
|
||||
liteflowConfig = new LiteflowConfig();
|
||||
}
|
||||
return buildDefaultExecutor(liteflowConfig.getWhenMaxWorkers(), liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenQueueLimit(), "lf-when-thead-");
|
||||
liteflowConfig.getWhenQueueLimit(), "when-thread-");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.CmpConfig.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* Spring Boot 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@TestPropertySource(value = "classpath:/maxWaitSeconds/application.properties")
|
||||
@SpringBootTest(classes = MaxWaitSecondsELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.maxWaitSeconds.cmp"})
|
||||
public class MaxWaitSecondsELDeclMultiSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "c")
|
||||
public void process(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = bindCmp.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY, "value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_IF, nodeId = "f", nodeType = NodeTypeEnum.IF)
|
||||
public boolean processIf(NodeComponent bindCmp) throws Exception {
|
||||
return true;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH, nodeId = "s", nodeType = NodeTypeEnum.SWITCH)
|
||||
public String processSwitch(NodeComponent bindCmp) throws Exception {
|
||||
return "b";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_WHILE, nodeId = "w", nodeType = NodeTypeEnum.WHILE)
|
||||
public boolean processWhile(NodeComponent bindCmp) throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(bindCmp.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(bindCmp.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_ITERATOR, nodeId = "x", nodeType = NodeTypeEnum.ITERATOR)
|
||||
public Iterator<?> processIterator(NodeComponent bindCmp) throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
liteflow.rule-source=maxWaitSeconds/flow.el.xml
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.ACmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.BCmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.CCmp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* Spring Boot 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@TestPropertySource(value = "classpath:/maxWaitSeconds/application.properties")
|
||||
@SpringBootTest(classes = MaxWaitSecondsELDeclSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({ "com.yomahub.liteflow.test.maxWaitSeconds.cmp" })
|
||||
public class MaxWaitSecondsELDeclSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp {
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp {
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp {
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = bindCmp.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY, "value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
@LiteflowCmpDefine(NodeTypeEnum.IF)
|
||||
public class FCmp {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_IF, nodeType = NodeTypeEnum.IF)
|
||||
public boolean processIf(NodeComponent bindCmp) throws Exception {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
@LiteflowComponent("s")
|
||||
@LiteflowCmpDefine(NodeTypeEnum.SWITCH)
|
||||
public class SCmp {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH, nodeType = NodeTypeEnum.SWITCH)
|
||||
public String processSwitch(NodeComponent bindCmp) throws Exception {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@LiteflowComponent("w")
|
||||
@LiteflowCmpDefine(NodeTypeEnum.WHILE)
|
||||
public class WCmp {
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_WHILE, nodeType = NodeTypeEnum.WHILE)
|
||||
public boolean processWhile(NodeComponent bindCmp) throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(bindCmp.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(bindCmp.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("x")
|
||||
@LiteflowCmpDefine(NodeTypeEnum.ITERATOR)
|
||||
public class XCmp {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_ITERATOR, nodeType = NodeTypeEnum.ITERATOR)
|
||||
public Iterator<?> processIterator(NodeComponent bindCmp) throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
liteflow.rule-source=maxWaitSeconds/flow.el.xml
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,203 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.ACmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.BCmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.CCmp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* 非 Spring 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public class MaxWaitSecondsTest extends BaseTest {
|
||||
|
||||
private static FlowExecutor flowExecutor;
|
||||
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
LiteflowConfig config = new LiteflowConfig();
|
||||
config.setRuleSource("maxWaitSeconds/flow.el.xml");
|
||||
flowExecutor = FlowExecutorHolder.loadInstance(config);
|
||||
}
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class BCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class CCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
|
||||
public class DCmp extends NodeComponent {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = this.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY, "value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
public class FCmp extends NodeIfComponent {
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
public class SCmp extends NodeSwitchComponent {
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class WCmp extends NodeWhileComponent {
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(this.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(this.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class XCmp extends NodeIteratorComponent {
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<nodes>
|
||||
<node id="a" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.ACmp"/>
|
||||
<node id="b" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.BCmp"/>
|
||||
<node id="c" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.CCmp"/>
|
||||
<node id="d" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp"/>
|
||||
<node id="f" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.FCmp"/>
|
||||
<node id="s" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.SCmp"/>
|
||||
<node id="w" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.WCmp"/>
|
||||
<node id="x" class="com.yomahub.liteflow.test.maxWaitSeconds.cmp.XCmp"/>
|
||||
</nodes>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,198 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.ACmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.BCmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.CCmp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
import org.noear.solon.test.annotation.TestPropertySource;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* Solon 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@ExtendWith(SolonJUnit5Extension.class)
|
||||
@TestPropertySource("classpath:/maxWaitSeconds/application.properties")
|
||||
public class MaxWaitSecondsSolonTest extends BaseTest {
|
||||
|
||||
@Inject
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp extends NodeComponent {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = this.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY, "value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
@LiteflowComponent("s")
|
||||
public class SCmp extends NodeSwitchComponent {
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@LiteflowComponent("w")
|
||||
public class WCmp extends NodeWhileComponent {
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(this.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(this.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("x")
|
||||
public class XCmp extends NodeIteratorComponent {
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
liteflow.rule-source=maxWaitSeconds/flow.el.xml
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.validateRule.cmp.ACmp;
|
||||
import com.yomahub.liteflow.test.validateRule.cmp.BCmp;
|
||||
import com.yomahub.liteflow.test.validateRule.cmp.CCmp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* Spring Boot 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@TestPropertySource(value = "classpath:/maxWaitSeconds/application.properties")
|
||||
@SpringBootTest(classes = MaxWaitSecondsELSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.maxWaitSeconds.cmp"})
|
||||
public class MaxWaitSecondsELSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
// WHEN 抛出的是 WhenTimeoutException
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp extends NodeComponent {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = this.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY,"value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
@LiteflowComponent("s")
|
||||
public class SCmp extends NodeSwitchComponent {
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@LiteflowComponent("w")
|
||||
public class WCmp extends NodeWhileComponent {
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(this.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(this.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("x")
|
||||
public class XCmp extends NodeIteratorComponent {
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
liteflow.rule-source=maxWaitSeconds/flow.el.xml
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,196 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.WhenTimeoutException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.ACmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.BCmp;
|
||||
import com.yomahub.liteflow.test.maxWaitSeconds.cmp.CCmp;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
|
||||
|
||||
/**
|
||||
* Spring 环境下超时控制测试
|
||||
*
|
||||
* @author DaleLee
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration("classpath:/maxWaitSeconds/application.xml")
|
||||
public class MaxWaitSecondsELSpringTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试 THEN 的超时情况
|
||||
@Test
|
||||
public void testThen1() {
|
||||
assertTimeout("then1");
|
||||
}
|
||||
|
||||
// 测试 THEN 的非超时情况
|
||||
@Test
|
||||
public void testThen2() {
|
||||
assertNotTimeout("then2");
|
||||
}
|
||||
|
||||
// 测试 When 的超时情况
|
||||
@Test
|
||||
public void testWhen1() {
|
||||
assertWhenTimeout("when1");
|
||||
}
|
||||
|
||||
// 测试 WHEN 的非超时情况
|
||||
@Test
|
||||
public void testWhen2() {
|
||||
assertNotTimeout("when2");
|
||||
}
|
||||
|
||||
// 测试 FOR 的超时情况
|
||||
@Test
|
||||
public void testFor1() {
|
||||
assertTimeout("for1");
|
||||
}
|
||||
|
||||
// 测试 FOR 的非超时情况
|
||||
@Test
|
||||
public void testFor2() {
|
||||
assertNotTimeout("for2");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的超时情况
|
||||
@Test
|
||||
public void testWhile1() {
|
||||
assertTimeout("while1");
|
||||
}
|
||||
|
||||
// 测试 WHILE 的非超时情况
|
||||
@Test
|
||||
public void testWhile2() {
|
||||
assertNotTimeout("while2");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的超时情况
|
||||
@Test
|
||||
public void testIterator1() {
|
||||
assertTimeout("iterator1");
|
||||
}
|
||||
|
||||
// 测试 ITERATOR 的非超时情况
|
||||
@Test
|
||||
public void testIterator2() {
|
||||
assertNotTimeout("iterator2");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的超时情况
|
||||
@Test
|
||||
public void testSwitch1() {
|
||||
assertTimeout("switch1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testSwitch2() {
|
||||
assertNotTimeout("switch2");
|
||||
}
|
||||
|
||||
// 测试 IF 的超时情况
|
||||
@Test
|
||||
public void testIf1() {
|
||||
assertTimeout("if1");
|
||||
}
|
||||
|
||||
// 测试 SWITCH 的非超时情况
|
||||
@Test
|
||||
public void testIf2() {
|
||||
assertNotTimeout("if2");
|
||||
}
|
||||
|
||||
// 测试单个组件的超时情况
|
||||
@Test
|
||||
public void testComponent1() {
|
||||
assertTimeout("component1");
|
||||
}
|
||||
|
||||
// 测试单个组件的非超时情况
|
||||
@Test
|
||||
public void testComponent2() {
|
||||
assertNotTimeout("component2");
|
||||
}
|
||||
|
||||
// 测试 FINALLY,虽然超时,但 FINALLY 仍会执行
|
||||
@Test
|
||||
public void testFinally1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
|
||||
DefaultContext contextBean = response.getFirstContextBean();
|
||||
Assertions.assertTrue(contextBean.hasData(CONTENT_KEY));
|
||||
}
|
||||
|
||||
// 测试 maxWaitSeconds 关键字不能作用于 Finally
|
||||
@Test
|
||||
public void testFinally2() {
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode()
|
||||
.setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, FINALLY(c).maxWaitSeconds(10))"));
|
||||
}
|
||||
|
||||
// 测试 chain 的超时情况
|
||||
@Test
|
||||
public void testChain1() {
|
||||
assertTimeout("chain1");
|
||||
}
|
||||
|
||||
// 测试 chain 的非超时情况
|
||||
@Test
|
||||
public void testChain2() {
|
||||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertWhenTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertNotTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp extends NodeComponent {
|
||||
|
||||
public static final String CONTENT_KEY = "testKey";
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
DefaultContext contextBean = this.getFirstContextBean();
|
||||
contextBean.setData(CONTENT_KEY, "value");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
@LiteflowComponent("s")
|
||||
public class SCmp extends NodeSwitchComponent {
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@LiteflowComponent("w")
|
||||
public class WCmp extends NodeWhileComponent {
|
||||
private int count = 0;
|
||||
|
||||
// 执行过的 chain
|
||||
Set<String> executedChain = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
// 判断是否切换了 chain
|
||||
if (!executedChain.contains(this.getCurrChainId())) {
|
||||
count = 0;
|
||||
executedChain.add(this.getCurrChainId());
|
||||
}
|
||||
count++;
|
||||
return count <= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("x")
|
||||
public class XCmp extends NodeIteratorComponent {
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
List<String> list = ListUtil.toList("one", "two");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
|
||||
|
||||
<context:component-scan base-package="com.yomahub.liteflow.test.maxWaitSeconds.cmp" />
|
||||
|
||||
<bean id="springAware" class="com.yomahub.liteflow.spi.spring.SpringAware"/>
|
||||
|
||||
<bean class="com.yomahub.liteflow.spring.ComponentScanner"/>
|
||||
|
||||
<bean id="liteflowConfig" class="com.yomahub.liteflow.property.LiteflowConfig">
|
||||
<property name="ruleSource" value="maxWaitSeconds/flow.el.xml"/>
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor" class="com.yomahub.liteflow.core.FlowExecutor">
|
||||
<constructor-arg name="liteflowConfig" ref="liteflowConfig"/>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<!--
|
||||
a=>1s b=>2s c=>5s
|
||||
-->
|
||||
<!-- 串行编排测试 -->
|
||||
<chain name="then1">
|
||||
<!-- 超时 -->
|
||||
THEN(a,b).maxWaitSeconds(2);
|
||||
</chain>
|
||||
<chain name="then2">
|
||||
<!-- 不超时 -->
|
||||
THEN(a,b).maxWaitSeconds(5);
|
||||
</chain>
|
||||
|
||||
<!-- 并行编排测试 -->
|
||||
<chain name="when1">
|
||||
<!-- 超时 -->
|
||||
WHEN(a,c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<chain name="when2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(a,b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 循环编排测试 -->
|
||||
<chain name="for1">
|
||||
<!-- 超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="for2">
|
||||
<!-- 不超时 -->
|
||||
FOR(2).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- w 循环两次 -->
|
||||
<chain name="while1">
|
||||
<!-- 超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="while2">
|
||||
<!-- 不超时 -->
|
||||
WHILE(w).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
<!-- x 迭代两次 -->
|
||||
<chain name="iterator1">
|
||||
<!-- 超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="iterator2">
|
||||
<!-- 不超时 -->
|
||||
ITERATOR(x).DO(a).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 选择编排测试 -->
|
||||
<!-- s 选择 b 组件 -->
|
||||
<chain name="switch1">
|
||||
<!-- 超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="switch2">
|
||||
<!-- 不超时 -->
|
||||
SWITCH(s).TO(a, b).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 条件编排测试 -->
|
||||
<!-- f 返回 true -->
|
||||
<chain name="if1">
|
||||
<!-- 超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="if2">
|
||||
<!-- 不超时 -->
|
||||
IF(f, b, c).maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<!-- 测试单个组件 -->
|
||||
<chain name="component1">
|
||||
<!-- 超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
c.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
<chain name="component2">
|
||||
<!-- 不超时 -->
|
||||
WHEN(
|
||||
a.maxWaitSeconds(2),
|
||||
b.maxWaitSeconds(3)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 FINALLY -->
|
||||
<chain name="finally">
|
||||
<!-- 超时,但 FINALLY 执行 -->
|
||||
THEN(PRE(a), b, FINALLY(d)).maxWaitSeconds(2);
|
||||
</chain>
|
||||
|
||||
<!-- 测试 chain -->
|
||||
<chain name="testChain">
|
||||
THEN(b)
|
||||
</chain>
|
||||
<chain name="chain1">
|
||||
<!-- 超时 -->
|
||||
testChain.maxWaitSeconds(1);
|
||||
</chain>
|
||||
<chain name="chain2">
|
||||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
</flow>
|
||||
Reference in New Issue
Block a user