How I Simplified Complex SMS Channel Selection with LiteFlow’s Rule Engine
Facing a tangled SMS routing system with many third‑party providers, I replaced cumbersome if‑else and serial queries with LiteFlow’s lightweight rule engine, using parallel checks, EL expressions, sub‑variables, and context‑based data flow to create a flexible, maintainable, and hot‑reloadable workflow, even for multithreaded tasks.
Background
In my company we needed to send SMS through multiple third‑party providers. Some business scenarios required selecting the provider with the most remaining quota, others forced a specific provider, and the selection logic changed frequently. The original code used many nested if‑else statements and serial queries, making it hard to maintain.
Why LiteFlow
During a team meeting a colleague introduced LiteFlow, an open‑source Chinese rule engine. LiteFlow can orchestrate arbitrarily complex flows, supports hot‑refresh, and uses a concise EL syntax (about ten keywords). It matched my requirements perfectly.
Simple Example
The corresponding LiteFlow rule is:
<chain name="chain1">
THEN(
a,
WHEN(b, THEN(c, d)),
e
)
</chain>Here THEN denotes serial execution and WHEN denotes parallel execution.
Complex Example
The rule becomes:
<chain name="chain1">
THEN(
A,
WHEN(
THEN(B, C),
THEN(D, E, F),
THEN(
SWITCH(G).to(
THEN(H, I, WHEN(J, K)).id("t1"),
THEN(L, M).id("t2")
),
N
)
),
Z
)
</chain>LiteFlow also supports sub‑variables, allowing the same logic to be written more clearly:
<chain name="chain1">
item1 = THEN(B, C);
item2 = THEN(D, E, F);
item3_1 = THEN(H, I, WHEN(J, K)).id("t1");
item3_2 = THEN(L, M).id("t2");
item3 = THEN(SWITCH(G).to(item3_1, item3_2), N);
THEN(
A,
WHEN(item1, item2, item3),
Z
);
</chain>My SMS Flow
Using the ideas above I expressed the whole SMS channel‑selection process as a LiteFlow XML flow:
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="channelSenderChain">
selectBestChannel = THEN(
WHEN(
channel1Query, channel2Query, channel3Query,
channel4Query, channel5Query, channel6Query
),
channelSelector
).id("branch1");
selectBizChannel = THEN(
biz1,
SWITCH(if_2).to(
channel3,
channel4,
SWITCH(if_3).to(channel5, channel6).id("s3")
).id("s2")
).id("branch2");
THEN(
packageData,
SWITCH(if_1).to(
channel1,
channel2,
selectBestChannel,
selectBizChannel
),
batchSender
);
</chain>
</flow>A useful tip I discovered: even the most complicated graph can be split into local sub‑variables, then referenced in the main flow, which lets me finish the whole definition in about ten minutes.
Execution is straightforward:
LiteflowResponse response = flowExecutor.execute2Resp("channelSenderChain", null, BatchMessageResultContext.class);
BatchMessageResultContext context = response.getFirstContextBean();
if (response.isSuccess()) {
log.info("Execution succeeded, final channel: {}", context.getFinalResultChannel());
} else {
log.error("Execution failed", response.getCause());
}Benefits
After refactoring, each logical block is completely decoupled and communicates only through the context . Changing business rules now only requires editing the corresponding component or rule file—no Java code changes or application restarts are needed (thanks to hot‑refresh). Components are reusable and their order can be rearranged freely.
LiteFlow also offers advanced features such as implicit flows, event callbacks, declarative components, component AOP, step information, custom thread pools, private delivery, and simple monitoring. The script component even supports Groovy, allowing logic changes without restarting the JVM.
Additional Use: Multithreaded Orchestration
Beyond SMS routing, LiteFlow can orchestrate asynchronous threads without writing explicit CompletableFuture code. The framework creates threads automatically; you just define each thread’s work as a component and describe the orchestration with EL.
String el = "THEN(
main1,
WHEN(
THEN(c1, c2, WHEN(c3, c4)),
THEN(c5, c6)
),
main2
)";
LiteFlowChainELBuilder.createChain()
.setChainName("testChain")
.setEL(el)
.build();
LiteflowResponse response = flowExecutor.execute2Resp("testChain", initParam, YourContext.class);This concise definition makes LiteFlow a great ally for developers who are not comfortable with low‑level multithreading.
Conclusion
LiteFlow proved to be a powerful, flexible rule engine that turned a messy, hard‑to‑maintain SMS routing codebase into a clean, modular, and hot‑reloadable solution, while also offering capabilities for multithreaded orchestration and script‑based extensions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
