Observability
Two pluggable surfaces, both no-op by default.
import { createRecordingObserver, createRecordingTracer } from 'octaflow';
const observer = createRecordingObserver(); // captures FlowEvents in memory (tests/introspection)const tracer = createRecordingTracer(); // captures spans in memoryconst engine = createWorkflowEngine({ store, dispatcher, registry, partitionKey, observer, tracer });FlowObserverreceives aFlowEventat every transition —workflow.started/completed/ failed/cancelledandstep.started/completed/failed/retrying/skipped/waiting/resumed/mapping/ compensating/compensated, each with{ workflowId, stepKey, stepType, attempt, durationMs, error, partitionKey, at }. One surface powers run history (persist the events) and metrics (feed OTel counters/histograms).FlowTracerwraps each step execution in aflow.stepspan (records the error on failure). An OpenTelemetry adapter is a ~10-linestartSpanshim.- Postgres run history:
createPgEventSink({ pool, partitionKey })is aFlowObserverthat appends toflow_step_event; read a run’s timeline back withreadFlowEvents(pool, { workflowId, partitionKey }). A step that retried/transitioned is fully reconstructable after the fact.