Skip to main content

nexora-runtime

ExecutionEngine — ties the planner and scheduler together into a single execution unit. You do not use this directly; NexoraEngine (in nexora-api) is the public entry point.

Responsibilities

  1. Accept an Intent and pass it to the CompositePlanner to produce a Plan.
  2. Create an ExecutionContext with a new traceId and executionId.
  3. Persist an ExecutionRecord via the ExecutionStore (if configured).
  4. Hand the Plan and context to the DagStepScheduler.
  5. On completion (success or failure), update the persisted record and fire a PlanCompleted/Failed event.

Execution flow

Intent
└─ CompositePlanner.plan()
└─ Plan
└─ DagStepScheduler.execute()
├─ Step A (no deps) ──► CapabilityInvoker ──► InterceptorPipeline
├─ Step B (no deps) ──► CapabilityInvoker ──► InterceptorPipeline
└─ Step C (deps: A,B) ──► (waits) ──► CapabilityInvoker
└─ ExecutionResult

Thread model

By default, the engine uses Executors.newVirtualThreadPerTaskExecutor() (Java 21 virtual threads). Each step runs on its own virtual thread, allowing thousands of concurrent steps with minimal OS thread overhead.

Override the executor to use a platform thread pool or a custom thread factory:

NexoraEngine engine = NexoraEngine.builder()
.withExecutor(Executors.newFixedThreadPool(20))
.build();

Async execution

NexoraEngine.execute() returns a CompletableFuture<ExecutionResult>. The future completes when the entire plan finishes (or fails).

engine.execute(intent)
.thenAccept(result -> log.info("status={}", result.status()))
.exceptionally(ex -> { log.error("Execution failed", ex); return null; });

Use .join() for synchronous callers, but be aware this will block the calling thread.