Backend Development 9 min read

Designing a Flexible Workflow Engine: From Simple Chains to Complex Nested Nodes

The article chronicles the step‑by‑step evolution of a custom workflow engine, detailing how sequential approvals, countersign, parallel, conditional, delegation, timeout, rejection, nesting, and scripting features were incrementally added to support increasingly complex business processes.

Java Captain
Java Captain
Java Captain
Designing a Flexible Workflow Engine: From Simple Chains to Complex Nested Nodes

When the boss first asked for a simple workflow engine, the author researched the concept and implemented a basic version that linked approvers in a linear list ending with a termination node.

After the boss demanded support for countersign (会签) nodes, the design shifted to a tree structure separating simple leaf nodes and complex internal nodes, introducing node states such as Ready, Complete, Future, and Waiting.

The engine then added parallel nodes, where any child node’s approval completes the parent, and introduced a new Skip state to deactivate sibling branches once one child succeeds.

Unlimited nesting was enabled, allowing any combination of countersign, parallel, and other complex nodes within the tree.

Conditional nodes were introduced to route the flow based on form data, acting like parallel nodes but only activating children whose conditions are satisfied.

Simple nodes were expanded into three types: fixed approver, form‑derived approver, and dynamic approver computed from the initiator (e.g., get_manager("Alice")).

Rejection capabilities were added: first, a reset to the initiator; then rejection to the previous approver, handling the complexity of nested structures.

Further, rejection to any arbitrary node was implemented by rolling back step‑by‑step until the target node became Ready.

A time‑limit feature was added so that nodes exceeding their allotted time display a timeout status.

Delegation (proxy) was introduced by inserting a parallel parent node and a sibling node for the delegate, supporting unlimited nesting of delegates.

Cancellation of delegation was added as the inverse operation, prohibited if the delegate had already approved.

Pre‑ and post‑conditions were attached to each node, requiring conditions to be met before entry and before completion.

To visualize progress, a percentage metric was calculated based on the distance from the leftmost node to the rightmost Ready node relative to the total width of the tree.

Finally, the engine allowed two scripts per node—one executed when the node starts approval and another when it finishes.

The complete system was eventually sold to several securities firms, and the author reflects on the intense development journey.

backendWorkflowstate machinedesigntreenodeapproval
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

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.