Riven processes all media pipeline work asynchronously through BullMQ backed by Redis. Queues are divided into three categories: flow queues that implement the core multi-step pipeline, plugin queues that fan events out to plugin hooks, and sandboxed worker queues that run CPU-intensive tasks in isolated Node.js worker threads. All queues connect to Redis viaDocumentation 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.
settings.redisUrl.
Queue Topology
Flow Queues
Flow queues power the core pipeline. Each queue has a corresponding BullMQFlowProducer-compatible schema that defines the job’s input, output, and allowed child jobs.
| Queue name | Purpose |
|---|---|
process-item-request | Fetches metadata from TMDB/TVDB and creates MediaItem entities |
process-media-item | Orchestrates a single media item through scrape → validate → download → complete |
request-content-services | Polls content source plugins (Overseerr, MDBList, …) for new requests |
scrape-item | Fans the scrape request to all enabled scraper plugins; collects stream candidates |
download-item | Drives the debrid cache check and download flow for a single item |
download-item.rank-streams | Ranks available streams by quality, resolution, and language preferences |
download-item.find-valid-torrent | Queries debrid provider(s) for cached availability; triggers download if needed |
request-stream-link | Acquires a play-ready stream URL and runs health-check loop |
request-subtitles | Post-processing step: requests subtitles from subtitle plugins |
post-process-media-item | Orchestrates post-download steps (stream link + subtitles) |
Plugin Queues
Every plugin that registers a hook for aRivenEvent type gets its own dedicated queue named using the pattern:
torrentio that handles riven.media-item.scrape.requested events will consume from the queue riven.media-item.scrape.requested.plugin[torrentio]. This isolation means a slow or failing plugin cannot block other plugins from processing the same event.
Sandboxed Worker Queues
Sandboxed workers run in isolated Node.js worker threads (useWorkerThreads: true) for CPU-heavy tasks that would otherwise block the event loop:
| Queue name | Task | Concurrency |
|---|---|---|
scrape-item.parse-scrape-results | Parse and normalise raw scraper responses | floor(parallelism × 0.25) |
download-item.map-items-to-files | Map torrent file trees to MediaItem entities | floor(parallelism × 0.75) |
download-item.validate-torrent-files | Validate torrent file integrity and naming | floor(parallelism × 0.25) |
Flow Orchestration
Riven uses BullMQ’sFlowProducer to build parent→child job trees. A parent job waits for all its children to complete before its own processor runs. This gives you multi-step pipelines with automatic dependency tracking and a single point of failure handling.
ProcessMediaItemFlow schema illustrates how steps are modelled as an enum on the job input — the processor checks job.data.step and re-enqueues with the next step value, turning a multi-step workflow into a linear state machine backed by the queue:
Deduplication
Jobs are assigned adeduplication.id option so that enqueuing the same logical work twice has no effect if the job is already waiting or active:
Deduplication IDs are scoped to the queue. Calling
clearDeduplicationJob(queueName, id) (used by the removeItemRequest mutation) removes the pending job and its deduplication record atomically.Retry Strategy
Flow Workers
Standard flow workers use BullMQ’s default retry behaviour with 3 attempts. The scrape worker has a custombackoffStrategy tied to settings.scrapeCooldownHours:
DataSource Workers (Plugin HTTP Clients)
BaseDataSource wraps every HTTP call in a BullMQ job. The retry strategy for HTTP requests uses these defaults:
| Setting | Default |
|---|---|
| Attempts | 3 |
| Base backoff delay | 10 000 ms |
| Non-fatal status codes | 408, 425, 429, 500, 502, 503, 504 |
404, 403) is treated as fatal and the job fails immediately without further retries.
Rate Limiting
BaseDataSource supports BullMQ’s built-in queue rate limiter via the optional rateLimiterOptions property. When an upstream API responds with HTTP 429, the DataSource calls queue.rateLimit(), which pauses the worker and re-queues the in-flight job to be retried after the duration specified in the Retry-After response header.
Concurrency
Flow worker concurrency defaults tofloor(availableParallelism() × 1.5) — biased above the CPU count because flow workers are primarily I/O-bound (database queries, HTTP calls). Sandboxed workers use lower multipliers because they perform CPU-bound parsing and validation.