跪拜 Guibai
← All articles
Backend

A 98KB Workflow Engine That Ships in Four Languages

By mldong ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Workflow engines in the Java ecosystem have grown heavy: Flowable ships 70+ tables and deep framework coupling. A 98KB core that runs without Spring, swaps databases through interfaces, and reproduces identical behavior in four languages changes the calculus for teams that want embeddable process automation without vendor lock-in.

Summary

jeeflow's Java engine core weighs 98KB and depends on nothing except slf4j-api. It runs in five lines of code with an in-memory repository, then connects to MySQL by swapping one SPI implementation — no Spring, no MyBatis, no JSON library binding. The engine abstracts every external concern into pluggable interfaces: six core SPIs cover repository, JSON parsing, user lookup, expression evaluation, ID generation, and transactions; five extension SPIs add organizational queries, candidate search, metadata, permissions, and management tables.

Inside, a DDD rich domain model treats state transitions as domain behavior. ProcessInstance and ProcessTask aggregates own their state changes — complete, reject, abandon, withdraw — through a dual-layer state machine with seven instance states and six task states. Nine built-in process patterns (task, decision, fork, join, sub-process, countersign, custom nodes) cover over 95% of approval scenarios, all exposed through a unified facade with 40 actions that a single forwarding controller can consume.

The same process JSON produces identical results across Java, Go, Python, and Node implementations. The database schema uses only eight tables, compared to Flowable's 70-plus.

Takeaways
jeeflow-core is 98KB and depends only on slf4j-api (provided scope); it has no compile-time dependency on Spring, MyBatis, or any JSON library.
Five lines of Java start a complete engine instance using an in-memory repository and a built-in JSON provider.
Six core SPI interfaces make every external concern pluggable: repository, JSON parsing, user lookup, expression evaluation, ID generation, and transactions.
Five extension SPIs add organizational queries, candidate search, metadata providers, action permissions, and management repository access.
The database schema uses 8 tables total — 5 core (define, instance, task, task_actor, cc) plus 3 management (design, design history, surrogate).
A DDD aggregate-root model puts state transitions inside ProcessInstance and ProcessTask, not in service-layer scripts.
The dual-layer state machine has 7 instance states and 6 task states, including withdrawn, terminated, suspended, and abandoned.
Nine process patterns are built in: start, end, task, decision, fork, join, sub-process, custom node, and countersign (parallel/serial/by ratio).
A unified facade exposes 40 actions covering definition, instance, task, design, delegation, and view endpoints.
Identical process JSON runs on Java, Go, Python, and Node implementations with the same results.
Conclusions

Keeping the core at 98KB while adding management extensions, persistence, metadata, permissions, and 40 facade actions across six days of releases suggests the SPI boundary was drawn correctly from the start — new capabilities land in the periphery without bloating the core.

The claim of 'zero dependencies' is precise: it means all dependencies are pluggable, not absent. The engine ships with a built-in JSON provider and memory repository so it runs immediately, but every integration point is an interface with swappable implementations.

Eight tables versus Flowable's 70-plus is not just aesthetic minimalism — it reduces operational surface area for migrations, backups, and troubleshooting, which matters more in embedded scenarios than in standalone workflow servers.

Shipping the same engine semantics in four languages with a single frontend consuming all four backends turns the project from a Java library into a cross-stack workflow standard, which is a more ambitious claim than the 98KB figure alone suggests.

Concepts & terms
SPI (Service Provider Interface)
A pattern where an application defines interfaces and lets external implementations be plugged in at runtime. jeeflow uses SPI to decouple the engine core from databases, JSON libraries, user directories, and transaction management.
DDD Aggregate Root
In Domain-Driven Design, an aggregate root is the top-level entity that enforces consistency rules for a cluster of related objects. jeeflow's ProcessInstance is the aggregate root that owns tasks and controls all state transitions.
Rich Domain Model
A design where business logic lives inside domain objects rather than in separate service layers. jeeflow's ProcessInstance and ProcessTask contain their own state-change methods (complete, reject, abandon) instead of relying on external CRUD scripts.
Countersign
A workflow pattern where multiple people must approve a task, either in parallel (all at once), serially (one after another), or by ratio (a percentage must approve). jeeflow supports all three modes.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗