feature #I7I3LL 增加TimeoutCondition

This commit is contained in:
Dale Lee
2023-07-12 11:38:11 +08:00
parent 605aab0694
commit 99413e6c3e
4 changed files with 112 additions and 20 deletions

View File

@@ -1,15 +1,13 @@
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.ConditionKey;
import com.yomahub.liteflow.flow.element.condition.FinallyCondition;
import com.yomahub.liteflow.flow.element.condition.ThenCondition;
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
import com.yomahub.liteflow.flow.element.condition.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -35,7 +33,7 @@ public class MaxWaitSecondsOperator extends BaseOperator<Condition> {
return whenCondition;
} else if (executable instanceof FinallyCondition) {
// FINALLY报错
String errorMsg = "The caller cannot be FinallyCondition item";
String errorMsg = StrFormatter.format("The caller [{}] cannot use the keyword \"maxWaitSeconds'\"", executable.toString());
throw new QLException(errorMsg);
} else if (containsFinally(executable)) {
// 处理 THEN 中的 FINALLY
@@ -43,26 +41,28 @@ public class MaxWaitSecondsOperator extends BaseOperator<Condition> {
return handleFinally(thenCondition, maxWaitSeconds);
} else {
// 其他情况,被 WHEN 包装
return wrappedByWhen(executable, maxWaitSeconds);
return wrappedByTimeout(executable, maxWaitSeconds);
}
}
/**
* 将一个 Executable 包装为带有单独超时控制的 WhenCondition
* @param executable 带包装对象
* 将一个 Executable 包装为带有单独超时控制的 TimeoutCondition
*
* @param executable 待包装对象
* @param maxWaitSeconds 最大等待秒数
* @return 包装后的 WhenCondition
* @return 包装后的 TimeoutCondition
*/
private WhenCondition wrappedByWhen(Executable executable, Integer maxWaitSeconds) {
WhenCondition whenCondition = new WhenCondition();
whenCondition.addExecutable(executable);
whenCondition.setMaxWaitTime(maxWaitSeconds);
whenCondition.setMaxWaitTimeUnit(TimeUnit.SECONDS);
return whenCondition;
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
*/
@@ -73,7 +73,8 @@ public class MaxWaitSecondsOperator extends BaseOperator<Condition> {
/**
* 将 FINALLY 排除在超时控制之外
* @param thenCondition 待处理的 ThenCondition
*
* @param thenCondition 待处理的 ThenCondition
* @param maxWaitSeconds 最大等待秒数
* @return 处理后的 ThenCondition
*/
@@ -95,7 +96,7 @@ public class MaxWaitSecondsOperator extends BaseOperator<Condition> {
finallyList.clear();
// 包装内部 THEN
WhenCondition whenCondition = wrappedByWhen(thenCondition, maxWaitSeconds);
WhenCondition whenCondition = wrappedByTimeout(thenCondition, maxWaitSeconds);
outerThenCondition.addExecutable(whenCondition);
return outerThenCondition;

View File

@@ -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";
}
}
}

View File

@@ -22,6 +22,8 @@ import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.concurrent.TimeoutException;
import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
/**
@@ -34,7 +36,7 @@ import static com.yomahub.liteflow.test.maxWaitSeconds.cmp.DCmp.CONTENT_KEY;
@TestPropertySource(value = "classpath:/maxWaitSeconds/application.properties")
@SpringBootTest(classes = MaxWaitSecondsELSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({ "com.yomahub.liteflow.test.maxWaitSeconds.cmp" })
@ComponentScan({"com.yomahub.liteflow.test.maxWaitSeconds.cmp"})
public class MaxWaitSecondsELSpringbootTest extends BaseTest {
@Resource
@@ -55,7 +57,8 @@ public class MaxWaitSecondsELSpringbootTest extends BaseTest {
// 测试 When 的超时情况
@Test
public void testWhen1() {
assertTimeout("when1");
// WHEN 抛出的是 WhenTimeoutException
assertWhenTimeout("when1");
}
// 测试 WHEN 的非超时情况
@@ -141,7 +144,7 @@ public class MaxWaitSecondsELSpringbootTest extends BaseTest {
public void testFinally1() {
LiteflowResponse response = flowExecutor.execute2Resp("finally", "arg");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals(WhenTimeoutException.class, response.getCause().getClass());
Assert.assertEquals(TimeoutException.class, response.getCause().getClass());
// FINALLY 执行时在默认数据上下文中放入了 CONTENT_KEY
DefaultContext contextBean = response.getFirstContextBean();
Assert.assertTrue(contextBean.hasData(CONTENT_KEY));
@@ -172,7 +175,25 @@ public class MaxWaitSecondsELSpringbootTest extends BaseTest {
Assert.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");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals(TimeoutException.class, response.getCause().getClass());
}
private void assertWhenTimeout(String chainId) {
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals(WhenTimeoutException.class, response.getCause().getClass());

View File

@@ -95,4 +95,16 @@
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>