Skip to content

Execution Engine ​

The Execution Engine is the runtime core of Fluxify. Every time an HTTP request is matched to a workflow, the engine takes over — it walks the block graph, passes data between steps, manages failures, and enforces time limits.

How the Engine Runs a Workflow ​

When a request arrives, the server assembles an Execution Context and then calls the engine's start() method with the ID of the first block to run (the Entrypoint).

Incoming Request
      │
      ▼
 Context Created (vars, scripting helpers, DB)
      │
      ▼
 Engine.start(entrypointBlockId)
      │
      ├─► Block A executes → output passed as `input` to Block B
      │
      ├─► Block B executes → output passed as `input` to Block C
      │
      ├─► Block C fails → Error Handler redirects to Block D
      │
      └─► Block D (Response) executes → engine stops, result returned

Step-by-Step ​

  1. Entrypoint: The engine starts at a designated block (typically the Entrypoint block tied to the route).
  2. Block execution: Each block's executeAsync() method is called with the previous block's output as params (accessible as input in scripts).
  3. Navigation: If a block returns a next field, the engine loads that block and continues. If next is absent, execution stops.
  4. Error handling: If a block fails and does not set continueIfFail: true, the engine routes to the configured Error Handler block. If the error handler has no continuation, execution stops.
  5. Final result: The last BlockOutput is returned to the request router, which serializes it into an HTTP response.

The Context & The Engine ​

The Engine receives the Execution Context in its EngineOptions. It does not read request data directly — all request awareness comes from the context:

typescript
export type EngineOptions = {
  errorHandlerId: string;          // ID of the fallback Error Handler block
  context: Context;                // The full execution context
};

Every block receives the full context via its constructor, giving it access to scripting helpers, the logger, DB, and HTTP client.

Route Timeout ​

Route timeouts are opt-in through the experimental experimental.workerTimeouts.enabled project setting. When enabled, each route has a 30-second timeout by default, or a configured timeout for that route. The worker supervisor can terminate a stalled worker that exceeds the route limit.

Tip: Keep database queries and external HTTP calls bounded and avoid unnecessary sequential round-trips. The worker-timeout protection is experimental and does not replace application-level timeouts for external services.

Error Handling ​

Every workflow must have an Error Handler block configured. The engine uses its ID (errorHandlerId) to route failures.

Failure flow:

  1. Block throws an exception or returns successful: false with continueIfFail: false.
  2. Engine calls errorBlock.executeAsync(error).
  3. If the error block returns a next block ID, execution resumes from there.
  4. If the error block has no next, the last failure result is returned.

continueIfFail flag: A block can signal that even on failure the engine should proceed to next. This is used by blocks like JS Runner (which always sets continueIfFail: true on success).

Block Output Contract ​

Every block must return a BlockOutput object:

typescript
interface BlockOutput {
  output?: any;           // The data to pass to the next block as `input`
  next?: string;          // ID of the next block to run (undefined = stop)
  error?: string;         // Error message (set on failure)
  successful: boolean;    // Whether this block succeeded
  continueIfFail: boolean; // If true, engine moves to `next` even on failure
}

Relationship to the Context ​

The engine is intentionally thin — it knows nothing about HTTP, databases, or scripting. All of that lives in the Context that surrounds it:

ConcernHandled by
Request parsinghandleRequest() in the request router
Variable statevars in the Context
Script executionNative JavaScript emitted by the DAG compiler and executed in Bun
DB accesscontext.dbFactory
Outgoing HTTPcontext.httpClient
Loggingcontext.vars.logger
Route timeoutExperimental worker supervisor (when enabled)

See Execution Context for the full context reference.

Performance ​

The engine is designed to be lightweight:

  • No I/O in the loop: The engine itself does zero I/O. All I/O happens inside blocks.
  • Concurrent requests: Because each request gets its own isolated context and engine instance, many requests can run in parallel without interference.
  • Single-threaded execution per workflow: Blocks within one workflow run sequentially (one at a time), ensuring predictable state management.

Released under the Apache License 2.0. Enterprise features are under the Fluxify Enterprise Edition License.