Skip to main content

Online edition for BLOGE 0.9.8-RC1 · facts verified 2026-09-15 · 中文

Chapter 1 — What BLOGE Is and Why It Exists

This chapter establishes a working understanding of what BLOGE is, why it exists, and which structural properties define it most clearly.


Learning Goals

  1. Describe BLOGE in one sentence without falling back to framework jargon.
  2. Name the three properties that make BLOGE different from ad-hoc orchestration: visible, structured, and resilient.
  3. Describe what a graph is at the conceptual level — a directed acyclic graph of business steps with explicit data and control flow.
  4. Explain why the engine, not the developer, should be responsible for concurrency, retry, and failure propagation.

Prerequisites

  • Basic Java knowledge (you don't need to be an expert).
  • A working JDK 25+ and Maven 3.6+ installation (see Getting Started).

Source Examples

FileWhat it shows
ch05/order-process.blogeA complete teaching workflow with fan-out, fan-in, branching, and resilience
ch03/bff-dashboard.blogeA BFF aggregation graph with five parallel fetches and mixed fallback strategies

30-Second Introduction

At a high level, BLOGE is an orchestration engine for business workflows. It does not replace business code itself; instead, it extracts runtime concerns such as dependency relationships, parallel execution, and failure handling from scattered implementations and organizes them into an explicit graph.

Defining BLOGE

BLOGE is a Java-first orchestration engine. It represents business workflows as graphs of nodes and dependencies, while the engine handles ordering, parallelism, retry, timeout, branching, waiting, and recovery. Runtime logic that would otherwise be scattered across service code is therefore collected into an explicit structure.

BLOGE extends beyond DAG-based graphs into higher-level orchestration patterns: multi-turn sessions (bloge-session-ext + bloge-session-durable), explicit state machines (bloge-state-ext + bloge-state-durable), and LLM-driven agent loops with tool dispatch (bloge-agent-ext). These capabilities are covered in later chapters — for now, the graph model is the foundation.

BLOGE stands for Biz Logic Orchestration Graph Engine. The expanded name states the system boundary directly: it is concerned with business logic, it solves an orchestration problem, it uses a graph as the execution model, and it relies on an engine to run that model.

In that sense, BLOGE is neither only a DSL nor only a diagramming tool. It combines a workflow model with a runtime engine; once workflow shape, dependencies, and failure policies are declared, the engine applies them to execution, concurrency control, and resilience behavior.

Three Design Properties Used in This Book

This book uses three properties to compare BLOGE with ad-hoc orchestration. They describe how the workflow is read, how execution is organized, and how runtime behavior is attached to the model; they are an explanatory frame, not an independent benchmark result.

  1. Visible — the workflow is presented directly as a graph, so business paths, branch points, and upstream-downstream relationships can be read from the model instead of reconstructed from service code.
  2. Structured — dependencies belong to the workflow model itself. Which nodes may run in parallel and which nodes must wait is determined by declared graph relationships rather than by the order of handwritten code.
  3. Resilient — retry, timeout, fallback, waiting, and durable progress are attached to the workflow as runtime policies. Failure handling therefore becomes part of the model instead of being scattered across ad-hoc glue code.

What BLOGE Is Not

Defining what BLOGE is not helps establish the boundary of the system just as clearly. The following interpretations are incomplete because they describe surface form without describing BLOGE as a workflow model plus runtime engine.

  1. It is not another wrapper around sequential code. If the only change were syntactic, execution shape would still be determined mainly by writing order; in BLOGE, execution shape is determined by dependencies declared in the graph.
  2. It is not only a diagramming tool. A graph here is not a static picture for documentation; it is a workflow model that the engine can read, schedule, and execute.
  3. It is not a system that leaves orchestration mechanics to each application team. Concurrency, retry, timeout, fallback, and waiting do not have to be rebuilt around every business step; the engine applies them consistently from the model.

The simplest accurate mental shorthand is this: BLOGE turns workflow intent into an explicit graph, then lets the engine carry the operational burden.


Why Not Hand-Written Orchestration

Knowing what BLOGE is is only the first step. The harder question is why teams should stop writing orchestration as sequential service code with ad-hoc retry, timeout, and recovery logic spread across multiple classes. That is where hand-written orchestration starts to fail.

Why This Matters

Most business systems start simple:

1. Fetch the user
2. Fetch the products
3. Calculate the price
4. Check credit
5. Create the order (or reject it)

In a plain service, you write this as sequential method calls. It works — until it doesn't:

  • Steps 1 and 2 are independent but you run them in sequence, wasting wall-clock time.
  • Step 4 can fail transiently, so you wrap it in a retry loop — and now your business logic is tangled with infrastructure.
  • Nobody can see the workflow. When something breaks at 2 AM, a developer has to read the code to reconstruct what happened.

This is the problem BLOGE exists to solve. Once you know that BLOGE is an engine for explicit workflow graphs, the value proposition becomes much clearer: you declare the shape of your workflow — which steps depend on which, what to do when something fails — and the engine handles scheduling, concurrency, and resilience for you.


Mental Model

Think of a BLOGE graph as a recipe card for the engine:

Diagram: 01-why-bloge figure 1

Each box is a node. Each arrow is a dependency. The engine reads this card and figures out:

  • fetchUser and fetchProducts have no dependencies on each other → run them in parallel.
  • calcPrice needs both → wait for both, then start.
  • checkCredit feeds a branch — the engine picks the right downstream node based on the result.

You describe what depends on what. The engine decides when to run what.


First Working Example

Here is a simplified extract from ch05/order-process.bloge:

graph orderProcess {

node fetchUser : FetchUserOperator {
input { userId = ctx.userId }
timeout = 3s
retry = { attempts: 2, backoff: 200ms, strategy: exponential }
}

node fetchProducts : FetchProductsOperator {
input { productIds = ctx.productIds }
timeout = 5s
}

node calcPrice : CalcPriceOperator {
depends_on = [fetchUser, fetchProducts]
input {
user = fetchUser.output
products = fetchProducts.output
}
}

node checkCredit : CreditCheckOperator {
depends_on = [fetchUser, calcPrice]
input {
userId = fetchUser.output.id
amount = calcPrice.output.total
}
retry = { attempts: 3, backoff: 100ms, strategy: jitter }
fallback = { approved: false, reason: "credit service unavailable" }
}

branch on checkCredit.output.approved {
true -> createOrder
false -> rejectOrder
}
}

Read it top to bottom:

  1. Two independent fetches — the engine will run them concurrently. fetchUser even has its own retry policy.
  2. A calculation node with an explicit depends_on that fans in from both fetches — the engine could also infer this from the .output references.
  3. A credit check (CreditCheckOperator) with retry and fallback — resilience declared right where the node is defined.
  4. A branch — not an if statement in your Java code, but a first-class routing decision in the graph.

Key insight: You never wrote a thread pool, a retry loop, or a try/catch for the fallback. The engine owns that.


Follow One Order: Move Responsibilities, Not Methods

Imagine OrderService.placeOrder() started as five readable calls. Six months later it also opens futures, retries credit checks, times out inventory, catches half a dozen exceptions, emits metrics, and decides whether to create or reject the order. The method still "works", but one place now owns both the business story and every mechanism required to run it.

Diagram: responsibility map from method to graph

Read the diagram as an ownership change

BLOGE does not improve the design merely by drawing boxes around those calls. The useful change is that each concern gets one visible owner:

QuestionVisible owner
What work exists?Nodes such as fetchUser, calcPrice, and createOrder
What must finish first?Dependency edges
What happens after a transient failure?The node's retry and timeout policy
Which business path was not selected?The result status SKIPPED
What did the business operation actually do?The Operator output and external evidence

This separation matters during change. Adding an inventory check changes the graph shape. Changing the pricing formula changes CalcPriceOperator. Changing the retry delay changes a node policy. A reviewer no longer has to rediscover all three decisions inside one control-flow method.

The first boundary to remember

An explicit graph makes the declared orchestration inspectable; it does not prove that an Operator charged the right amount or that the workflow satisfies the business requirement. Chapters 18 and 23–32 add those stronger forms of evidence. For now, the win is narrower and concrete: the execution shape has stopped hiding inside incidental Java control flow.

The Module Map — Now You Have a Reason to Read It

The order story gives each layer a job. Core runs the graph; authoring tools make the declaration readable; extensions add larger interaction models; runtime integrations retain and observe execution.

Diagram: 01-why-bloge figure 2

Layer 1 — Core

ModuleWhat it provides
bloge-coreGraph model, scheduler, listener/interceptor APIs, and GraphEngine.
bloge-runtime-spiExecution, checkpoint, wait, timer, lease, audit, and inbox store contracts.

Layer 2 — Authoring

ModuleWhat it provides
bloge-dsl.bloge parser, compiler, and code generator.
bloge-lang / bloge-lspShared language model and editor diagnostics.
bloge-lint / bloge-studioReproducible rules and visual graph authoring.
bloge-maven-pluginOperator metadata generation.

Layer 3 — Extensions

ModuleWhat it provides
bloge-session-ext / bloge-state-extMulti-turn sessions and explicit state machines.
bloge-agent-extModel/tool loops with bounded capabilities.
bloge-event-journalAppend-only execution and agent events.

Layer 4 — Runtime and integrations

ModuleWhat it provides
bloge-durable / bloge-durable-mybatisRecovery and persistent execution state.
bloge-spring / bloge-spring-webBoot wiring, web errors, and the operations console.
bloge-metrics-otel / bloge-dispatch-kafkaTelemetry and remote-worker dispatch.
bloge-test / bloge-verificationGraph tests and business-correctness evidence.

Start with bloge-core and bloge-dsl. Add a layer only when the story reaches its problem; the rest of the book returns to this map at those moments.


Break It Apart

ConceptWhat it means
graphA named container for the workflow — a DAG of nodes
nodeA single processing step that runs an operator
input { … }Bindings that wire upstream outputs and context values into the node's input
ctx.userIdA value from the graph context — the initial data passed to the engine at execution time
fetchUser.outputThe output of an upstream node — referencing it creates an implicit dependency
timeoutA wall-clock duration limit for the node
retryAutomatic re-execution on failure with a backoff strategy
fallbackA static result to use if the node still fails after retries
branch onConditional routing that activates one downstream path based on a node's output

Common Trap

❌ Treating nodes like function calls

// DON'T think like this:
User user = fetchUser(ctx.getUserId());
List<Product> products = fetchProducts(ctx.getProductIds());
Price price = calcPrice(user, products);

In procedural code the order of lines is the execution order. In BLOGE the dependency graph is the execution order. If two nodes don't reference each other's output, the engine is free to run them at the same time.

Think in dependencies, not in sequences.


Guided Rewrite

Look at the ch03/bff-dashboard.bloge example. It fetches five data sources for a dashboard:

graph bffDashboard {

node fetchProfile : FetchProfileOperator {
input { userId = ctx.userId }
timeout = 2s
retry = { attempts: 1, backoff: 100ms }
}

node fetchOrders : FetchOrdersOperator {
input { userId = ctx.userId }
timeout = 3s
fallback = { recentOrderIds: [], totalOrders: 0 }
}

// … fetchRecommendations, fetchNotifications, fetchLoyalty …

node aggregate : AggregateOperator {
depends_on = [fetchProfile, fetchOrders, fetchRecommendations, fetchNotifications, fetchLoyalty]
input {
profile = fetchProfile.output
orders = fetchOrders.output
recommendations = fetchRecommendations.output
notifications = fetchNotifications.output
loyalty = fetchLoyalty.output
}
}
}

Questions to consider:

  1. How many nodes run in parallel? (Answer: all five fetch nodes — none depends on another.)
  2. What happens if fetchOrders fails or times out? (Answer: fetchOrders has no retry policy — it only has a fallback. If it fails the fallback value { recentOrderIds: [], totalOrders: 0 } is used and the graph continues with partial data.)
  3. If you added a sixth fetch that depended on fetchProfile.output, would it still run in parallel with the other fetches? (Answer: no — it would wait for fetchProfile to complete first.)

Brain Check

  1. What are the three properties that distinguish a BLOGE graph from ad-hoc orchestration code? (Visible, structured, resilient.)
  2. Who decides whether two nodes run concurrently — the developer or the engine? (The engine, based on the dependency graph.)
  3. In the order-process example, what happens if checkCredit fails after all three retry attempts? (The fallback value is used: { approved: false, reason: "credit service unavailable" }.)

Lab

Open ch05/order-process.bloge in your editor.

  1. Add a fetchInventory node that runs in parallel with fetchUser and fetchProducts. Give it a timeout of 2s.
  2. Wire its output into calcPrice by adding an input binding.
  3. Predict the new execution shape: which nodes now run in parallel? Which wait?

Compilation can wait here. The immediate goal is to make the shape of the DSL readable before moving on to execution in Chapter 2.


Experiment acceptance card

  • Expected and observed: Dependencies and resilience policies are visible in DSL, and the execution shape can be labelled.
  • Failure and recovery: Reference a missing output; remove the bad edge and redraw the DAG.
  • Proof boundary: Proves reviewable design intent, not compilation, execution, or business correctness.
  • Exercise contract: Order DSL; add only the inventory node and one binding; deliver a dependency sketch; stop when every edge has a source and the graph is acyclic.

Recap

  • BLOGE replaces hand-written orchestration with a visible, structured, resilient graph.
  • A graph is a DAG of nodes. Each node runs an operator.
  • The engine reads dependencies (explicit or inferred from .output references) and schedules nodes accordingly.
  • Resilience (timeout, retry, fallback) is declared on the node, not buried in business code.
  • Branches route control flow based on a node's output.

Next Step

Chapter 2 — Your First Graph continues with the smallest graph that can be written, compiled, and executed end to end.


Coding Agent: Open the versioned task guide.