Streaming Mode
Streaming mode emits events in real time as the simulation runs, rather than collecting them all at the end. Enable it with time: { stream: true } in your generate() call.
Basic Usage
typescript
import { generate, defineJourney } from '@synode/core';
import { CallbackAdapter } from '@synode/core';
const adapter = new CallbackAdapter((event) => {
console.log(event.name, event.timestamp);
});
await generate(journey, {
time: { duration: '1h', stream: true },
simulation: { users: 50, lanes: 4, tick: '5m' },
adapter,
});Pacing
Control how fast the simulation clock advances using simulation.pacing:
typescript
// As fast as possible (default)
simulation: { users: 500, lanes: 8, tick: '15m', pacing: 'none' }
// Real-time: wall-clock matches simulated time
simulation: { users: 500, lanes: 8, tick: '15m', pacing: 'realtime' }
// Accelerated: 10x faster than real-time
simulation: { users: 500, lanes: 8, tick: '15m', pacing: { mode: 'realtime', speed: 10 } }
// Fixed delay between each tick
simulation: { users: 500, lanes: 8, tick: '15m', pacing: { mode: 'fixed', delayMs: 100 } }Live Ingestion Example
Stream generated events directly to a webhook in real time:
typescript
import { generate } from '@synode/core';
import { HttpAdapter } from '@synode/adapter-http';
await generate([browseJourney, purchaseJourney], {
time: { duration: '24h', stream: true },
simulation: {
users: 200,
lanes: 4,
tick: '10m',
pacing: { mode: 'realtime', speed: 60 }, // 1 simulated hour per real minute
},
adapter: new HttpAdapter({
url: 'https://ingest.example.com/events',
batchSize: 50,
}),
});Continuous Simulation
Use time: { stream: true } with an AbortSignal to run an endless simulation that you stop externally:
typescript
import { generate } from '@synode/core';
import { CallbackAdapter } from '@synode/core';
const controller = new AbortController();
setTimeout(() => controller.abort(), 60_000); // stop after 1 minute
await generate(journey, {
time: { stream: true },
simulation: {
users: Infinity,
lanes: 8,
tick: '1m',
pacing: 'realtime',
},
adapter: new CallbackAdapter((event) => ingest(event)),
signal: controller.signal,
});How It Works
In streaming mode the simulator advances the clock one tick at a time and flushes events from that tick before moving to the next. Events are emitted in simulated-timestamp order within each tick.
Without streaming, the simulator runs to completion and the adapter receives all events at the end (or batched as configured by the adapter itself).
