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.

Programmer DD
Programmer DD
Programmer DD
How I Simplified Complex SMS Channel Selection with LiteFlow’s Rule Engine

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

Simple flow diagram
Simple flow diagram

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

Complex flow diagram
Complex flow diagram

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.

Multithreaded flow diagram
Multithreaded flow diagram
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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javarule engineworkflowhot-reloadLiteFlowparallel processingEL Expressions
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.