From Simple Chain to Dynamic Tree: Building a Flexible Workflow Engine Step by Step

The article walks through the evolution of a custom workflow engine, starting with a linear approval chain and progressively adding parallel, conditional, nested, and proxy nodes, while introducing node states, time limits, scripts, and progress metrics to handle increasingly complex business requirements.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
From Simple Chain to Dynamic Tree: Building a Flexible Workflow Engine Step by Step

Level 1

A boss asked for a simple workflow engine. After researching workflow concepts, the author built a version where approvers are added sequentially as a linked list, with a final end node. The current approver is recorded and moves forward after approval; the process ends when the end node is reached.

Sequentially add any number of approvers to form a chain, ending with an end node.

Record the current approver; after approval, move to the next approver.

The process finishes when the end node is reached.

The boss thought it was a bit crude.

Level 2

The boss then demanded support for countersign (joint approval) nodes. After learning that a countersign node contains many approvers and only completes when all have approved, the author redesigned the engine, abandoning the linked‑list approach.

Structural changes:

Nodes are divided into simple (rectangular) and complex (circular) types.

The whole process is represented as a tree; leaf nodes are simple nodes.

Each simple node contains exactly one approver.

Complex nodes contain multiple child nodes.

Countersign nodes activate all child nodes; the countersign node completes when all children are approved.

Serial nodes require children to be approved left‑to‑right; the node completes after the last child.

The outermost layer of any workflow is a serial node representing overall completion.

Node statuses were introduced:

Ready : Simple node ready for approval.

Complete : Node already approved.

Future : Node not yet reached.

Waiting : Complex node waiting for child approvals.

An example workflow with a countersign node is illustrated with diagrams.

The boss found it interesting.

Level 3

The boss requested parallel nodes. A parallel node is a complex node where any child’s approval completes the node.

Parallel node activates all children; when any child reaches the Complete state, the parallel node is considered complete.

A new status Skip was added: when a child of a parallel node is not in Ready or Waiting, its sibling nodes and their descendants are set to Skip.

An example diagram demonstrates this behavior.

The boss noted that adding new nodes was now easy.

Level 4

The boss wanted unlimited nesting (e.g., a countersign node containing a parallel node, which in turn contains a complex node). The existing tree structure already supports arbitrary depth.

The expandable tree can represent any complex process.

The boss praised the design.

Level 5

The boss added a requirement for conditional nodes: the workflow includes a form, and the next branch depends on form values.

The author introduced a conditional node, similar to a parallel node but only child nodes whose conditions are satisfied become active.

The boss approved.

Level 6

The boss wanted three types of approvers: fixed, derived from the form, or calculated from the initiator via a mapping function (e.g., get_manager("Qian") → "Li").

The simple node was split into three categories accordingly.

The boss was satisfied.

Level 7

The boss asked if a node could be rejected backward to the previous approver.

The author implemented a “reject to initiator” feature, effectively restarting the workflow.

Only nodes in Ready state can reject, mirroring the approval permission.

The boss joked about laziness.

Level 8

Next, the boss wanted “reject to previous approver”. Because of unlimited nesting, determining the previous approvers was complex.

The author eventually implemented this feature.

The boss marked it as read.

Level 9

The boss demanded “reject to any node”. The solution: repeatedly reject to the previous level until a Ready node containing the target node is reached.

The boss acknowledged.

Level 10

A time‑limit was added to ordinary nodes; if not completed within the limit, the node shows as timed out.

The author implemented it despite surprise.

The author humorously noted that requirements and hair loss are inversely related.

Level 11

The boss introduced a proxy feature: if an approver is unsure, they can forward the task to a more suitable person.

Since previous node relationships were fixed before workflow start, this required a new design.

Create a parallel node as the parent of the original node, then add a sibling node for the proxy approver, allowing either to approve.

Proxying can be nested indefinitely; a proxy can itself be proxied.

Level 12

The boss asked for a “cancel proxy” function.

Canceling proxy is the inverse operation of proxying.

If the proxy approver has already approved, cancellation is not allowed.

Level 13

The boss wanted pre‑ and post‑conditions for each node: a node can only be entered when its pre‑condition is met, and can only complete when its post‑condition is satisfied.

The author added these checks, which doubled the related code.

Level 14

With increasingly complex workflows, the boss asked for a progress indicator showing the percentage of completion.

The metric is calculated as the distance from the leftmost node to the rightmost Ready node divided by the total distance to the rightmost node in the tree.

Level 15

Finally, the boss requested that each node support two executable scripts: one triggered when the node starts approval, and another when the node finishes approval.

The author implemented this, noting that his hair was now completely gone.

Afterword

The boss, a Tsinghua graduate, eventually sold this workflow system to several securities firms. The author moved on to other companies, reflecting on the intense overtime and hair loss that accompanied the development of this system three years ago.

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.

workflowapproval processnode-typesengine design
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.