Riven’s entire application lifecycle is driven by XState v5 state machines. Rather than a tangled web of callbacks or ad-hoc async initialisation, every state transition is explicit, typed, and recoverable. Three machines cooperate to take Riven from cold start to a fully running media pipeline: the Bootstrap machine, the Plugin Registrar machine (invoked by Bootstrap), and the Main Runner machine.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/rivenmedia/riven-ts/llms.txt
Use this file to discover all available pages before exploring further.
Bootstrap Machine
Machine ID:"Bootstrap"
The Bootstrap machine runs once at startup and proceeds through a strictly ordered sequence of states. Each state invokes a promise-based actor; a failure in any state transitions to the terminal Errored state and throws to the process supervisor.
State-by-state walkthrough
State-by-state walkthrough
Bootstrapping database connection
Invokes the
initialiseDatabaseConnection actor. Establishes the
MikroORM connection pool to PostgreSQL. On failure, transitions
immediately to Errored.Clearing previous instance state
Invokes
clearPreviousInstanceState with flags from settings:
unsafeWipeDatabaseOnStartup and unsafeWipeRedisOnStartup. Resets
any stale in-progress job state from a previous crash. After success,
branches to Applying mock scenario if a mock scenario was provided,
otherwise goes straight to Bootstrapping plugins.Applying mock scenario (conditional)
Invokes
applyMockScenario with the scenario object. Used exclusively
in integration tests to seed a known database state before the runner
starts. Skipped entirely in production.Bootstrapping plugins
Invokes the
pluginRegistrarMachine child machine (see below). On
completion, the handlePluginValidationResponse action populates
validPlugins, invalidPlugins, pluginQueues, pluginWorkers,
and publishableEvents on the context. If any plugins failed
validation, Riven logs a warning but continues.Initialising services (parallel state)
A parallel state with a single region:
Bootstrapping GraphQL Server.
Invokes startGqlServer with the validated plugin map and plugin
settings. On success, the Apollo server instance is stored in context
via assignGqlServer. Transitions to Bootstrapping VFS when all
parallel regions reach final.Bootstrapping VFS
Invokes
initialiseVfs with settings.vfsMountPath. On success,
stores the Fuse instance in context via assignVfs. Transitions to
Success.Bootstrap Context and Output
Bootstrap throws if it completes without a server or VFS instance. These are
considered fatal preconditions — the machine output type asserts their
presence at runtime.
Main Runner Machine
Machine ID:"Riven program main runner"
The Main Runner is the long-lived orchestrator. It starts in Idle, transitions to Running when it receives a START event from the Program machine, and only ever leaves Running if an unrecoverable error forces it into the terminal Errored state.
Startup Sequence
When theSTART event arrives, a single assign action performs several things atomically:
- Stores the validated plugin map, queues, workers, and publishable events on context.
- Creates all flow workers (standard BullMQ workers for the core pipeline queues).
- Creates all sandboxed workers (isolated worker threads for CPU-intensive tasks).
entry actions of Running:
- Raise
riven.core.started(notifies plugin hooks that Riven is live). - Raise
riven-internal.request-content-services(immediately polls content sources). - Raise
riven-internal.retry-library(re-queues any incomplete items from a previous run).
Event Handling in Running
TheRunning state handles every RivenEvent type. The jobEnqueuer actor is invoked as a persistent service that receives forwarded events; it enqueues them to the appropriate plugin queues. The shouldQueueEvent guard prevents events from accumulating if no plugins have registered hooks for them.
Error Recovery and Graceful Shutdown
Job-Level Retry
Flow workers use BullMQ’s built-in retry with exponential backoff. The
scrape worker uses a custom
backoffStrategy based on
settings.scrapeCooldownHours — 30 min → hours-based tiers at attempt
2, 5, and 10.Library Retry
On startup and on a schedule,
riven-internal.retry-library re-queues any
ItemRequest or MediaItem that is stuck in an incomplete state from a
previous run or crash.Graceful Shutdown
The
handleGracefulShutdown action sends riven.core.shutdown to the
parent Program machine, which coordinates draining BullMQ workers and
unmounting the VFS before the process exits.Errored (final)
If the Main Runner enters
Errored, it logs a fatal message and halts.
This state is only reachable from an unrecoverable internal error — normal
event handling errors are swallowed and logged per-event.Integration with the Event System
State machines and the event bus are tightly coupled by design:- The Main Runner’s
sendmethod (self.send) is passed directly to every flow worker assendEvent, allowing job processors to fire events back into the machine. - The
jobEnqueueractor receives forwarded events from theRunningstate’salwaystransition and fans them out to plugin queues. - The
publishableEventsset (built during Bootstrap) acts as a filter — events with no registered plugin hooks are never enqueued, preventing unbounded Redis growth.