Designing a Flexible Workflow Engine: From Simple Chains to Complex Nested Nodes
This article narrates the step‑by‑step design of a workflow engine, starting with a linear approval chain and progressively adding parallel, conditional, nested, proxy, timing, and scripting capabilities, illustrating how each new requirement reshapes the underlying tree‑structured state machine.
Hello, I am a senior architect sharing how I built a simple workflow engine for my boss and gradually extended it to handle increasingly complex requirements.
Level 1
The boss asked for a simple workflow engine. I created a linear chain of approvers ending with a terminal node, recording the current approver and moving to the next after approval. The boss found it too simplistic.
Append any number of approvers in order to form a linked list, then add an end node.
Track the current approver; after approval, move to the next approver.
When the approver reaches the end node, the process finishes.
Level 2
The boss then demanded support for "countersign" nodes, where a large node contains many approvers and all must approve before proceeding. I abandoned the linked‑list design and switched to a tree representation.
Classify nodes into simple (rectangles) and complex (circles).
Represent the whole process as a tree; leaf nodes are simple nodes.
Each simple node has exactly one approver.
Complex nodes contain multiple child nodes.
Countersign nodes activate all child nodes; the node completes when all children are approved.
Serial nodes allow children to be approved left‑to‑right; the node completes after the last child.
The outermost node of any workflow is a serial node whose completion marks the workflow’s end.
Level 3
The boss asked for parallel nodes, where any one approver’s success completes the node. I added a new state Skip and defined its behavior.
When a parallel node’s child is not in (Ready, Waiting), sibling nodes and their descendants become Skip .
Level 4
The boss wanted nested nodes (e.g., a countersign node containing a parallel node, which in turn contains a complex node). The tree structure already supports unlimited nesting.
Level 5
To support conditional branching based on form data, I introduced a conditional node that behaves like a parallel node but only activates children whose conditions are satisfied.
Level 6
I expanded simple nodes into three types: hard‑coded approver, approver read from the form, and approver derived from a mapping function (e.g., get_manager("Qian") → Li ).
Level 7
I added a reject‑to‑origin feature, allowing only Ready nodes to reject, which resets the workflow to the start.
Level 8
Rejecting to the previous approver required traversing the potentially infinite nested tree to locate the last approver; I finally implemented this logic.
Level 9
For arbitrary‑node rejection, I repeatedly reject to the previous level until a Ready node containing the target appears.
Level 10
I added a time‑limit to ordinary nodes; if the limit expires without approval, the node shows as timed‑out.
Level 11
Proxy functionality was added by creating a parallel parent node and a sibling proxy node, allowing both the original approver and the proxy to approve; proxies can be nested indefinitely.
Level 12
Canceling a proxy is simply the inverse operation; it is prohibited if the proxy has already approved.
Level 13
Pre‑ and post‑conditions were added to each node, requiring the pre‑condition to be satisfied before entry and the post‑condition before completion, significantly increasing code complexity.
Level 14
I introduced a progress metric that calculates the percentage of a running workflow by comparing the distance from the leftmost node to the rightmost Ready node against the total width of the tree.
Level 15
Finally, each node can attach two scripts: one executed when the node starts approval and another when it finishes, completing the feature set.
After years of development, the system was sold to several securities firms, and I moved on to other opportunities.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.