流程编排
前一篇笔记我们介绍了LiteFlow中的各种组件,这篇笔记我们介绍如何使用表达式编排这些组件实现我们的业务逻辑。
串行编排
THEN关键字用于串行编排,前面我们已经使用过了,下面例子a、b、c会顺序执行。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(a, b, c);
</chain>
</flow>
注意:THEN必须是大写。
并行编排
WHEN关键字用于并行编排,其中执行的组件会在默认的线程池中并发执行,我们可以通过测量执行时间或打印线程ID证明这一点。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
WHEN(a, b, c);
</chain>
</flow>
并行编排和串行编排可以组合使用。下面例子会先执行a,再并发执行bcd,最后执行e。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(
a,
WHEN(b, c, d),
e
);
</chain>
</flow>
下面例子更复杂一些,会先执行a,然后并发执行b和串行的cd,最后执行e。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(
a,
WHEN(b, THEN(c, d)),
e
);
</chain>
</flow>
忽略错误
ignoreError()可用于配置并行编排时,如果有一条路径执行出错,是否继续执行。下面例子中,即使b、c、d中执行出错,最终e也会执行。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(
a,
WHEN(b, c, d).ignoreError(true),
e
);
</chain>
</flow>
任一节点执行完忽略其它
any可以实现并行编排中任一节点执行完忽略其它,下面例子中,b、串行c和d、e中任一路径执行完成后,f就将被执行。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(
a,
WHEN(b, THEN(c, d), e).any(true),
f
);
</chain>
</flow>
选择编排
选择编排使用SWITCH...TO语法。下面例子中,a是一个选择组件,它返回被选中的nodeId,最后to()中符合条件的节点将被执行。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
SWITCH(a).TO(b, c, d);
</chain>
</flow>
SWITCH...TO语法也支持DEFAULT,用于在选择组件返回的结果没有符合的组件时,执行默认处理。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
SWITCH(a).TO(b, c).DEFAULT(d);
</chain>
</flow>
当选择的结果是表达式时,可以使用id()给表达式添加一个ID,下面例子中当选择组件返回cd时THEN(c, d)将被执行。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
SWITCH(a).TO(b, THEN(c, d).id("cd"));
</chain>
</flow>
条件编排
条件编排类似开发中的if...else if...else...逻辑。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
IF(x1, a).ELIF(x2, b).ELIF(x3, c).ELIF(x4, d).ELSE(e);
</chain>
</flow>
其中如果没有ELIF、ELSE逻辑可以将其省略。
对于非常简单的判断,我们也可以使用二元表达式代替,下面两个写法是等效的。
IF(x, a).ELSE(b);
IF(x, a, b);
循环编排
FOR循环
FOR循环能否循环固定的次数,使用FOR...DO语法实现,下面例子循环5次。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
FOR(5).DO(THEN(a, b));
</chain>
</flow>
如果次数的不确定的,则需要用到前一章节介绍的次数循环组件。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
FOR(x).DO(THEN(a, b));
</chain>
</flow>
WHILE循环
WHILE循环使用WHILE...DO语法实现,传入的不是循环次数而是循环的终止条件,这个条件需要使用布尔组件实现。下面例子中,每次执行循环体后都会再次执行布尔组件,返回true则继续执行,返回false则终止循环。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
WHILE(w).DO(THEN(a, b));
</chain>
</flow>
ITERATOR迭代循环
ITERATOR迭代循环使用ITERATOR...DO语法,需要配合迭代循环组件使用,常用于对集合元素的迭代。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
ITERATOR(x).DO(THEN(a, b));
</chain>
</flow>
异常捕获
异常捕获可以使用CATCH...DO语法,下面例子中,如果节点a执行出错,b就不会继续执行了,而是执行c。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
CATCH(
THEN(a, b)
).DO(c)
</chain>
</flow>
c组件中,可以通过this.getSlot().getException()获取异常对象,以便根据不同的异常类型进行不同处理。如果没有任何错误处理,DO也可以省略。
与或非
多个布尔组件可以使用与或非操作连接。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
IF(AND(x,y), a, b);
</chain>
</flow>
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
IF(OR(x,y), a, b);
</chain>
</flow>
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
IF(NOT(x), a, b);
</chain>
</flow>
调用子流程
前面我们介绍过,XML配置中的chain可以嵌套,对于较复杂的流程,我们可以通过合理的划分chain来提升流程表达式的可读性和可复用性。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="mainChain">
THEN(
A, B,
WHEN(chain1, D, chain2),
SWITCH(X).to(M, N, chain3),
z
);
</chain>
<chain name="chain1">
THEN(C, WHEN(J, K));
</chain>
<chain name="chain2">
THEN(H, I);
</chain>
<chain name="chain3">
WHEN(Q, THEN(P, R)).id("w01");
</chain>
</flow>
子流程其实还有一种更精简优美的写法,子流程可以定义为变量,并被主流程调用。对于仅需要在一个chain内复用的子流程,推荐使用这种写法。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain>
t1 = THEN(C, WHEN(J, K));
w1 = WHEN(Q, THEN(P, R)).id("w01");
t2 = THEN(H, I);
THEN(
A, B,
WHEN(t1, D, t2),
SWITCH(X).to(M, N, w1),
Z
);
</chain>
</flow>
重试
下面例子中,当b执行出现异常时会自动重试至多3次。如果3次都执行不成功则流程就会中断,最终的LiteflowResponse的isSuccess也会被设置为false,并带上对应的异常信息。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(a, b.retry(3));
</chain>
</flow>
除了单独的组件,表达式或子流程也都可以实现重试,下面是一些例子。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(a, b).retry(3);
</chain>
</flow>
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
FOR(c).DO(a).retry(3);
</chain>
</flow>
此外重试也可以指定异常类型,下面例子只在出现NullPointerException和ArrayIndexOutOfBoundsException时重试,抛出其它类型异常时不重试,直接中断流程。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(a, b).retry(3, "java.lang.NullPointerException", "java.lang.ArrayIndexOutOfBoundsException");
</chain>
</flow>
超时控制
maxWaitSeconds()和maxWaitMilliseconds()可用于对任意组件、表达式、子流程实现超时控制,两者分别指定超时的秒和毫秒数。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(a).maxWaitMilliseconds(500);
</chain>
</flow>
当超时发生时,流程会抛出java.util.concurrent.TimeoutException异常。