diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/pom.xml b/liteflow-rule-plugin/liteflow-rule-etcd/pom.xml new file mode 100644 index 000000000..ebee4d69e --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/pom.xml @@ -0,0 +1,27 @@ + + + + liteflow-rule-plugin + com.yomahub + ${revision} + ../pom.xml + + 4.0.0 + + liteflow-rule-etcd + + + + com.yomahub + liteflow-core + ${revision} + true + + + io.etcd + jetcd-core + + + \ No newline at end of file diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdClient.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdClient.java new file mode 100644 index 000000000..8983ce9f9 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdClient.java @@ -0,0 +1,127 @@ +package com.yomahub.liteflow.parser.etcd; + +import cn.hutool.core.collection.CollUtil; +import io.etcd.jetcd.ByteSequence; +import io.etcd.jetcd.Client; +import io.etcd.jetcd.KeyValue; +import io.etcd.jetcd.Watch; +import io.etcd.jetcd.watch.WatchEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * Etcd 客户端封装类. + * @author zendwang + * @since 2.9.0 + */ +public class EtcdClient { + + private static final Logger LOG = LoggerFactory.getLogger(EtcdClient.class); + + private Client client; + + private final ConcurrentHashMap watchCache = new ConcurrentHashMap<>(); + + public EtcdClient(final Client client) { + this.client = client; + } + + /** + * close client. + */ + public void close() { + this.client.close(); + } + + /** + * get node value. + * + * @param key node name + * @return string + */ + public String get(final String key) { + List keyValues = null; + try { + keyValues = client.getKVClient().get(ByteSequence.from(key, StandardCharsets.UTF_8)).get().getKvs(); + } catch (InterruptedException | ExecutionException e) { + LOG.error(e.getMessage(), e); + } + + if (CollUtil.isEmpty(keyValues)) { + return null; + } + + return keyValues.iterator().next().getValue().toString(StandardCharsets.UTF_8); + } + + /** + * put a key-value pair into etcd. + * @param key node name + * @param value node value + * @return + */ + public KeyValue put(final String key, final String value) { + KeyValue prevKv = null; + ByteSequence keyByteSequence = ByteSequence.from(key, StandardCharsets.UTF_8); + ByteSequence valueByteSequence = ByteSequence.from(value, StandardCharsets.UTF_8); + try { + prevKv = client.getKVClient().put(keyByteSequence, valueByteSequence).get().getPrevKv(); + } catch (InterruptedException | ExecutionException e) { + LOG.error(e.getMessage(), e); + } + return prevKv; + } + + /** + * subscribe data change. + * + * @param key node name + * @param updateHandler node value handler of update + * @param deleteHandler node value handler of delete + */ + public void watchDataChange(final String key, + final BiConsumer updateHandler, + final Consumer deleteHandler) { + Watch.Listener listener = watch(updateHandler, deleteHandler); + Watch.Watcher watch = client.getWatchClient().watch(ByteSequence.from(key, StandardCharsets.UTF_8), listener); + watchCache.put(key, watch); + } + + private Watch.Listener watch(final BiConsumer updateHandler, + final Consumer deleteHandler) { + return Watch.listener(response -> { + for (WatchEvent event : response.getEvents()) { + String path = event.getKeyValue().getKey().toString(StandardCharsets.UTF_8); + String value = event.getKeyValue().getValue().toString(StandardCharsets.UTF_8); + switch (event.getEventType()) { + case PUT: + updateHandler.accept(path, value); + continue; + case DELETE: + deleteHandler.accept(path); + continue; + default: + } + } + }); + } + + /** + * cancel subscribe. + * + * @param key node name + */ + public void watchClose(final String key) { + if (watchCache.containsKey(key)) { + watchCache.get(key).close(); + watchCache.remove(key); + } + } +} \ No newline at end of file diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdXmlELParser.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdXmlELParser.java new file mode 100644 index 000000000..99252655d --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/EtcdXmlELParser.java @@ -0,0 +1,65 @@ +package com.yomahub.liteflow.parser.etcd; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.parser.el.ClassXmlFlowELParser; +import com.yomahub.liteflow.parser.etcd.exception.EtcdException; +import com.yomahub.liteflow.parser.etcd.util.EtcdParserHelper; +import com.yomahub.liteflow.parser.etcd.vo.EtcdParserVO; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.util.JsonUtil; + +import java.util.function.Consumer; + +/** + * Etcd解析器实现,只支持EL形式的XML,不支持其他的形式 + * @author zendwang + * @since 2.9.0 + */ +public class EtcdXmlELParser extends ClassXmlFlowELParser { + + private final EtcdParserHelper etcdParserHelper; + + public EtcdXmlELParser() { + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + + if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData())){ + throw new EtcdException("rule-source-ext-data is empty"); + } + + try{ + EtcdParserVO etcdParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), EtcdParserVO.class); + assert etcdParserVO != null; + + if (StrUtil.isBlank(etcdParserVO.getNodePath())){ + etcdParserVO.setNodePath("/lite-flow/flow"); + } + if (StrUtil.isBlank(etcdParserVO.getConnectStr())){ + throw new EtcdException("Etcd connect string is empty"); + } + + etcdParserHelper = new EtcdParserHelper(etcdParserVO); + }catch (Exception e){ + throw new EtcdException(e.getMessage()); + } + } + + @Override + public String parseCustom() { + Consumer parseConsumer = t -> { + try { + parse(t); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + try { + String content = etcdParserHelper.getContent(); + etcdParserHelper.checkContent(content); + etcdParserHelper.listen(parseConsumer); + return content; + } catch (Exception e){ + throw new EtcdException(e.getMessage()); + } + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/exception/EtcdException.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/exception/EtcdException.java new file mode 100644 index 000000000..fb2f1d408 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/exception/EtcdException.java @@ -0,0 +1,28 @@ + +package com.yomahub.liteflow.parser.etcd.exception; + +/** + * Etcd解析异常 + * @author zendwang + * @since 2.9.0 + */ +public class EtcdException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** 异常信息 */ + private String message; + + public EtcdException(String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/util/EtcdParserHelper.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/util/EtcdParserHelper.java new file mode 100644 index 000000000..6c45f36a2 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/util/EtcdParserHelper.java @@ -0,0 +1,72 @@ +package com.yomahub.liteflow.parser.etcd.util; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.exception.ParseException; +import com.yomahub.liteflow.parser.el.XmlFlowELParser; +import com.yomahub.liteflow.parser.etcd.EtcdClient; +import com.yomahub.liteflow.parser.etcd.exception.EtcdException; +import com.yomahub.liteflow.parser.etcd.vo.EtcdParserVO; +import com.yomahub.liteflow.spi.holder.ContextAwareHolder; +import io.etcd.jetcd.Client; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.function.Consumer; + +/** + * @author zendwang + * @since 2.9.0 + */ +public class EtcdParserHelper { + + private static final Logger LOG = LoggerFactory.getLogger(EtcdParserHelper.class); + + private final EtcdParserVO etcdParserVO; + + private EtcdClient etcdClient; + + public EtcdParserHelper(EtcdParserVO etcdParserVO) { + this.etcdParserVO = etcdParserVO; + + try{ + this.etcdClient = ContextAwareHolder.loadContextAware().getBean(EtcdClient.class); + if (this.etcdClient == null) { + Client client = Client.builder() + .endpoints(etcdParserVO.getConnectStr().split(",")) + .build(); + this.etcdClient = new EtcdClient(client); + } + }catch (Exception e){ + throw new EtcdException(e.getMessage()); + } + } + + public String getContent(){ + try{ + return this.etcdClient.get(etcdParserVO.getNodePath()); + }catch (Exception e){ + throw new EtcdException(e.getMessage()); + } + } + + /** + * 检查 content 是否合法 + */ + public void checkContent(String content) { + if (StrUtil.isBlank(content)) { + String error = MessageFormat.format("the node[{0}] value is empty", etcdParserVO.getNodePath()); + throw new ParseException(error); + } + } + + /** + * 监听 etcd 节点 + */ + public void listen(Consumer parseConsumer) { + this.etcdClient.watchDataChange(this.etcdParserVO.getNodePath(), (updatePath, updateValue) -> { + LOG.info("starting load flow config...."); + parseConsumer.accept(updateValue); + }, null); + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/vo/EtcdParserVO.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/vo/EtcdParserVO.java new file mode 100644 index 000000000..c7e5b291a --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/etcd/vo/EtcdParserVO.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.parser.etcd.vo; + +/** + * 用于解析RuleSourceExtData的vo类,用于etcd模式中 + * @author zendwang + * @since 2.9.0 + */ +public class EtcdParserVO { + + private String connectStr; + + private String nodePath; + + public String getConnectStr() { + return connectStr; + } + + public void setConnectStr(String connectStr) { + this.connectStr = connectStr; + } + + public String getNodePath() { + return nodePath; + } + + public void setNodePath(String nodePath) { + this.nodePath = nodePath; + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/spi/etcd/EtcdParserClassNameSpi.java b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/spi/etcd/EtcdParserClassNameSpi.java new file mode 100644 index 000000000..72c6b7f63 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/java/com/yomahub/liteflow/parser/spi/etcd/EtcdParserClassNameSpi.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.parser.spi.etcd; + + +import com.yomahub.liteflow.parser.etcd.EtcdXmlELParser; +import com.yomahub.liteflow.parser.spi.ParserClassNameSpi; + + +/** + * Etcd解析器SPI实现 + * @author zendwang + * @since 2.9.0 + */ +public class EtcdParserClassNameSpi implements ParserClassNameSpi { + @Override + public String getSpiClassName() { + return EtcdXmlELParser.class.getName(); + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-etcd/src/main/resources/META-INF/services/com.yomahub.liteflow.parser.spi.ParserClassNameSpi b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/resources/META-INF/services/com.yomahub.liteflow.parser.spi.ParserClassNameSpi new file mode 100644 index 000000000..f418cfdf7 --- /dev/null +++ b/liteflow-rule-plugin/liteflow-rule-etcd/src/main/resources/META-INF/services/com.yomahub.liteflow.parser.spi.ParserClassNameSpi @@ -0,0 +1 @@ +com.yomahub.liteflow.parser.spi.etcd.EtcdParserClassNameSpi \ No newline at end of file diff --git a/liteflow-rule-plugin/pom.xml b/liteflow-rule-plugin/pom.xml index 9599dbec3..bc05dc7b3 100644 --- a/liteflow-rule-plugin/pom.xml +++ b/liteflow-rule-plugin/pom.xml @@ -13,6 +13,7 @@ liteflow-rule-zk liteflow-rule-sql + liteflow-rule-etcd liteflow-rule-plugin diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/pom.xml b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/pom.xml new file mode 100644 index 000000000..5fdf91f6b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/pom.xml @@ -0,0 +1,57 @@ + + + + liteflow-testcase-el + com.yomahub + ${revision} + ../pom.xml + + 4.0.0 + + liteflow-testcase-el-etcd-springboot + + + + com.yomahub + liteflow-spring-boot-starter + ${revision} + + + + com.yomahub + liteflow-rule-etcd + ${revision} + test + + + + org.springframework.boot + spring-boot-starter-test + + + org.aspectj + aspectjweaver + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${springboot.version} + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java new file mode 100644 index 000000000..64886670f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.test; + +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner; +import com.yomahub.liteflow.spring.ComponentScanner; +import com.yomahub.liteflow.thread.ExecutorHelper; +import org.junit.AfterClass; + +public class BaseTest { + + @AfterClass + public static void cleanScanCache(){ + ComponentScanner.cleanCache(); + FlowBus.cleanCache(); + ExecutorHelper.loadInstance().clearExecutorServiceMap(); + SpiFactoryCleaner.clean(); + LiteflowConfigGetter.clean(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/EtcdWithXmlELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/EtcdWithXmlELSpringbootTest.java new file mode 100644 index 000000000..f1756512a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/EtcdWithXmlELSpringbootTest.java @@ -0,0 +1,66 @@ +package com.yomahub.liteflow.test.etcd; + +import cn.hutool.core.util.ReflectUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.parser.etcd.EtcdClient; +import com.yomahub.liteflow.parser.etcd.EtcdXmlELParser; +import com.yomahub.liteflow.parser.etcd.util.EtcdParserHelper; +import com.yomahub.liteflow.spi.holder.ContextAwareHolder; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.*; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.function.Consumer; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * springboot环境下的etcd 规则解析器 测试 + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/etcd/application-xml-cluster.properties") +@SpringBootTest(classes = EtcdWithXmlELSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.etcd.cmp"}) +public class EtcdWithXmlELSpringbootTest extends BaseTest { + + @MockBean(answer= Answers.RETURNS_MOCKS) + private EtcdClient etcdClient; + + @Resource + private FlowExecutor flowExecutor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + String flowXml = "THEN(a, b, c);"; + String changedFlowXml = "THEN(a, c);"; + when(etcdClient.get(any())).thenReturn(flowXml).thenReturn(changedFlowXml); + } + + @Test + public void testEtcdNodeWithXml() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertTrue("a==>b==>c".equals(response.getExecuteStepStr())); + + // 手动触发一次 模拟节点数据变更 + EtcdXmlELParser parser = ContextAwareHolder.loadContextAware().getBean(EtcdXmlELParser.class); + parser.parse(etcdClient.get("/lite-flow/flow")); + + LiteflowResponse response2 = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response2.isSuccess()); + Assert.assertTrue("a==>c".equals(response2.getExecuteStepStr())); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/cmp/ACmp.java new file mode 100644 index 000000000..6d1ae42c8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/java/com/yomahub/liteflow/test/etcd/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

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

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

Title: liteflow

+ *

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

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

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.etcd.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml-cluster.properties b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml-cluster.properties new file mode 100644 index 000000000..211b3b4ec --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml-cluster.properties @@ -0,0 +1,2 @@ +liteflow.rule-source-ext-data={"connectStr":"http://localhost:2379,http://localhost:3379,http://localhost:4379"} +liteflow.parse-on-start=false diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml.properties b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml.properties new file mode 100644 index 000000000..3938e12e9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/application-xml.properties @@ -0,0 +1 @@ +liteflow.rule-source-ext-data={"connectStr":"http://localhost:2379"} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/flow.xml new file mode 100644 index 000000000..049210cf4 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-etcd-springboot/src/test/resources/etcd/flow.xml @@ -0,0 +1,6 @@ + + + + THEN(a, b, c); + + \ No newline at end of file diff --git a/liteflow-testcase-el/pom.xml b/liteflow-testcase-el/pom.xml index c31339763..550b63df3 100644 --- a/liteflow-testcase-el/pom.xml +++ b/liteflow-testcase-el/pom.xml @@ -24,5 +24,6 @@ liteflow-testcase-el-script-qlexpress-springboot liteflow-testcase-el-zk-springboot liteflow-testcase-el-sql-springboot + liteflow-testcase-el-etcd-springboot \ No newline at end of file diff --git a/pom.xml b/pom.xml index f9186b488..8d44a7293 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ 2.12.3 5.1.0 0.10 + 0.5.0 3.3.0 3.0.8 1.11.13 @@ -167,7 +168,11 @@ zkclient ${zkclient.version} - + + io.etcd + jetcd-core + ${jetcd.version} + com.alibaba QLExpress @@ -324,7 +329,7 @@ liteflow-spring liteflow-testcase-old liteflow-testcase-el - +