Skip to content

Execution

Source: packages/core/src/core/execution/runner.ts, packages/core/src/core/execution/engine.ts, packages/core/src/core/state/context.ts, packages/core/src/core/execution/pool.ts, packages/core/src/core/execution/worker.ts

generate

typescript
async function generate(journey: Journey | Journey[], options: RunOptions): Promise<void>;

Main entry point for synthetic data generation. Accepts a single journey or an array. Orchestrates dataset hydration, user creation, and event output through the configured adapter.

RunOptions

typescript
interface RunOptions {
  users: number; // Total users to simulate (0-10M)
  persona?: PersonaDefinition; // Persona for user attribute generation
  datasets?: DatasetDefinition[]; // Definitions to hydrate before execution
  preloadedDatasets?: Dataset[]; // Pre-populated datasets to inject
  lanes?: number; // Concurrent async lanes (default: 1)
  adapter?: OutputAdapter; // Output destination (default: ConsoleAdapter)
  debug?: boolean; // Enable telemetry (default: false)
  telemetryPath?: string; // Telemetry output path (default: './telemetry-report.json')
  startDate?: Date; // Start of date range (requires endDate)
  endDate?: Date; // End of date range (requires startDate)
  eventSchema?: EventSchemaConfig; // Zod schema validation for events
  workerModule?: string; // Module path for worker thread parallelism
  workers?: number; // Worker thread count (default: CPU cores)
}

Execution modes:

ConfigurationModeDetails
DefaultSequentialSingle-threaded, one user at a time
lanes > 1Parallel lanesPromise.all concurrency in the main thread
workerModule setWorker threadsTrue multi-core parallelism via worker_threads
typescript
import { generate, InMemoryAdapter } from '@synode/core';

const adapter = new InMemoryAdapter();
await generate(journey, {
  users: 1000,
  lanes: 4,
  persona: shoppers,
  datasets: [productsDef],
  adapter,
});

Engine

Internal class that executes a single journey against a context, yielding events as an async generator. Documented for advanced use cases (custom runners, testing).

typescript
class Engine {
  constructor(journey: Journey);
  async *run(context?: SynodeContext): AsyncGenerator<Event>;
}

The engine handles:

  • Prerequisite checks (journey.requires)
  • Journey-level and adventure-level bounce evaluation
  • Sequential adventure and action execution
  • Scope cleanup (action, adventure, journey) after each phase
  • Suppression period delays
  • Wrapping handler errors in SynodeError with code HANDLER_ERROR
  • Validating handler return type (must be Event[])
typescript
import { Engine, SynodeContext } from '@synode/core';

const engine = new Engine(journey);
const ctx = new SynodeContext();

for await (const event of engine.run(ctx)) {
  console.log(event.name, event.timestamp);
}

SynodeContext

Implementation of the Context interface. Manages per-user state, timing, datasets, and identity.

typescript
class SynodeContext implements Context {
  constructor(startTime?: Date, idGenerator?: IdGenerator, locale?: string);

  // Context interface methods
  get userId(): string;
  get sessionId(): string;
  get faker(): Faker;
  readonly locale: string;

  get<T>(key: string): T | undefined;
  set<T>(key: string, value: T, options?: ContextSetOptions): void;
  now(): Date;
  generateId(prefix?: string): string;
  hasCompletedJourney(journeyId: string): boolean;
  markJourneyComplete(journeyId: string): void;
  dataset(id: string): DatasetHandle;
  typedDataset<TRow extends DatasetRow>(id: string): DatasetHandle<TRow>;

  // Internal methods (used by Engine)
  registerDataset(dataset: Dataset): void;
  advanceTime(ms: number): void;
  rotateSession(): void;
  clearScope(scope: ContextScope): void;
}

Key behaviors:

  • set() with a scope means the field is auto-cleared when that scope ends
  • dataset() / typedDataset() throw SynodeError (DATASET_NOT_FOUND) with "Did you mean..." suggestions
  • now() returns a copy of the internal clock (safe to mutate)
  • rotateSession() generates a new session ID (called per journey)

WorkerPool

Internal class that manages worker threads for true multi-core parallelism. Used automatically when workerModule is set in RunOptions.

typescript
class WorkerPool {
  constructor(options: WorkerPoolOptions);
  async run(): Promise<void>;
}

Worker modules must export { journeys: Journey[] } and optionally persona, datasets, and preloadedDatasets. Datasets are serialized via structured clone and rehydrated in each worker.