Backend Development 7 min read

Master Workflow Orchestration to Simplify Business Logic with Flow Engines

This article explains why workflow orchestration is essential for isolating business logic in large systems, outlines common pitfalls of tangled if‑else code, and demonstrates how to configure and execute flow chains using a Java flow engine and plugin extensions.

macrozheng
macrozheng
macrozheng
Master Workflow Orchestration to Simplify Business Logic with Flow Engines

As a good programmer, keep solutions simple and avoid over‑design. I once dismissed workflow orchestration as unnecessary, but working in a middle‑platform team showed its importance for isolating business logic.

When many business lines share a system, adding new features without a workflow engine leads to tangled

if‑else

code, making maintenance risky and testing impossible.

The main pain points are code isolation and extensibility. Two practical solutions are:

Use a workflow engine to configure separate execution chains for each business scenario.

Use a plugin‑extension engine so each business can implement its own variations.

MemberClub demonstrates extensive use of a workflow engine and plugin‑extension engine to solve these problems.

Configuring the Execution Chain

DemoMemberPurchaseExtension shows how to define three different execution chain configurations for various member products.

Defining Flow Nodes

Each node implements

process

,

success

,

rollback

, and

callback

methods.

Executing the Flow

Call

FlowChain.execute

with a context object to run the chain.

During execution, nodes are linked like a responsibility chain:

process

runs sequentially, on exception

rollback

runs, and after all succeed

success

runs in reverse order, followed by

callback

.

FlowChain.execute Implementation

<code>public <T> void execute(FlowChain<T> chain, T context) {
    Exception exception = null;
    int index = -1;
    for (FlowNode<T> node : chain.getNodes()) {
        try {
            node.process(context);
            index++;
        } catch (Exception e) {
            if (e instanceof SkipException) {
                CommonLog.warn("Current flow:{} sent Skip request, stop later flows", node.getClass().getSimpleName());
                break;
            }
            exception = e;
            break;
        }
    }

    if (exception != null) {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.rollback(context, exception);
            } catch (Exception e) {
                CommonLog.error("rollback execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
            }
        }
    } else {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.success(context);
            } catch (Exception e) {
                CommonLog.error("success execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
            }
        }
    }

    for (int i = index; i >= 0; i--) {
        FlowNode<T> node = chain.getNodes().get(i);
        try {
            node.callback(context, exception);
        } catch (Exception e) {
            CommonLog.error("callback execution exception, ignore name:{}", node.getClass().getSimpleName(), e);
        }
    }
    if (exception != null) {
        throw exception;
    }
}
</code>

Project Source

Source code: https://gitee.com/juejinwuyang/memberclub

javaflow engineworkflowbackend developmentprocess orchestration
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login 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.