Scheduled Tasks
RomM runs background work through RQ (Redis Queue). Tasks fall into four categories:
- Scheduled: cron-driven, run on their own
- Watcher: triggered by filesystem events
- Manual: user-triggered from the UI or API
- Enqueued: side effects of user actions (a scan on the
/scanpage, a metadata refresh on a ROM edit, etc.)
The full table
| Task | Type | Default schedule | Enable var | Schedule/delay var | Purpose |
|---|---|---|---|---|---|
| Scheduled rescan | Scheduled | 0 3 * * * |
ENABLE_SCHEDULED_RESCAN |
SCHEDULED_RESCAN_CRON |
Rescans the entire library. |
| Scheduled LaunchBox metadata update | Scheduled | 0 4 * * * |
ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA |
SCHEDULED_UPDATE_LAUNCHBOX_METADATA_CRON |
Updates the LaunchBox metadata store. |
| Scheduled Switch TitleDB update | Scheduled | 0 4 * * * |
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB |
SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON |
Updates the Nintendo Switch TitleDB file. |
| Build recommendations index | Scheduled | 30 5 * * * |
ENABLE_SCHEDULED_BUILD_RECOMMENDATIONS |
SCHEDULED_BUILD_RECOMMENDATIONS_CRON |
Rebuilds the similar-games index from library metadata, play history and collections. |
| Convert images to WebP | Scheduled | 0 4 * * * |
ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP |
SCHEDULED_CONVERT_IMAGES_TO_WEBP_CRON |
Convert existing image files (PNG, JPG, BMP, TIFF, GIF) to WebP format for better performance. |
| Scheduled ZIP cache cleanup | Scheduled | 0 4 * * * |
ENABLE_SCHEDULED_CLEANUP_ZIP_CACHE |
SCHEDULED_CLEANUP_ZIP_CACHE_CRON |
Removes stale cached ZIP files based on tiered TTL. |
| Scheduled conversion cache cleanup | Scheduled | 0 4 * * * |
- |
- |
Removes stale converted download files based on TTL. Always on, not configurable. |
| Cleanup orphaned resources | Scheduled | 0 5 * * * |
ENABLE_SCHEDULED_CLEANUP_ORPHANED_RESOURCES |
SCHEDULED_CLEANUP_ORPHANED_RESOURCES_CRON |
Clean up orphaned resources in the ROMs directory. |
| Scheduled netplay cleanup | Scheduled | */30 * * * * |
ENABLE_SCHEDULED_CLEANUP_NETPLAY |
SCHEDULED_CLEANUP_NETPLAY_CRON |
Cleans up empty netplay rooms. |
| Scheduled upload tmp cleanup | Scheduled | 0 * * * * |
ENABLE_SCHEDULED_CLEANUP_UPLOAD_TMP |
SCHEDULED_CLEANUP_UPLOAD_TMP_CRON |
Cleans up orphaned chunked-upload temp directories. |
| Scheduled streaming session reaper | Scheduled | * * * * * |
- |
- |
Stops streaming sessions whose player stopped sending heartbeats. Runs only while emulator streaming is enabled. |
| Scheduled sync session cleanup | Scheduled | 23 * * * * |
ENABLE_SCHEDULED_CLEANUP_SYNC_SESSIONS |
SCHEDULED_CLEANUP_SYNC_SESSIONS_CRON |
Fails sync sessions no client ever completed. |
| Scheduled audit log cleanup | Scheduled | 30 4 * * * |
AUDIT_LOG_RETENTION_DAYS |
- |
Removes audit log events older than AUDIT_LOG_RETENTION_DAYS days. Runs while AUDIT_LOG_RETENTION_DAYS > 0. |
| Scheduled RetroAchievements progress sync | Scheduled | 0 4 * * * |
ENABLE_SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC |
SCHEDULED_RETROACHIEVEMENTS_PROGRESS_SYNC_CRON |
Updates RetroAchievements progress for all users. |
| Push-Pull Sync | Scheduled | */30 * * * * |
ENABLE_SYNC_PUSH_PULL |
SYNC_PUSH_PULL_CRON |
Sync saves with devices via SSH/SFTP. |
| Cleanup missing ROMs | Manual | - |
- |
- |
Delete all ROMs flagged as missing from the filesystem from the database. |
| Cleanup missing firmware | Manual | - |
- |
- |
Delete all firmware flagged as missing from the filesystem from the database. |
| Sync Folder Scan | Manual | - |
ENABLE_SYNC_FOLDER_WATCHER |
- |
Scan device sync folders for new save files. |
| Recompute save content hashes | Manual | - |
- |
- |
Re-scan every save row and rewrite content_hash with the current compute_content_hash algorithm. One-time recovery after the zip-hash dispatch fix. |
| Convert library | Manual | - |
ROM_CONVERTO_ENABLED |
- |
Convert each matched ROM to its platform's library format, replacing the original files. |
| Filesystem watcher | Watcher | - |
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE |
RESCAN_ON_FILESYSTEM_CHANGE_DELAY |
Watch the library folder and trigger a rescan on changes. |
| Sync folder watcher | Watcher | - |
ENABLE_SYNC_FOLDER_WATCHER |
SYNC_FOLDER_SCAN_DELAY |
Watch the sync folder and trigger a scan on changes. |
Configuring cadence
Every scheduled task takes a standard 5-field cron expression:
0 3 * * *: 3 AM daily0 */6 * * *: every 6 hours, on the hour*/30 * * * *: every 30 minutes0 2 * * 0: 2 AM every Sunday
Set the env var and restart the container. The scheduler picks up the new schedule as soon as RomM is back. An expression that doesn't parse leaves the task unscheduled, and the startup log names the task and the rejected expression.
Enabling a scheduled task
Most tasks have an ENABLE_* environment variable, like ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA=true which enables the LaunchBox sync. Set both the enable var and its cron var, since a task with an empty cron string has nothing to schedule and stays unscheduled even when enabled.
Unlike other tasks, build recommendations index ships enabled, because the recommendation sections read that index and similar games sits empty without it. Setting ENABLE_SCHEDULED_BUILD_RECOMMENDATIONS=false stops the nightly rebuild, but doesn't hide either section. Users turn those off in their own settings.
The housekeeping tasks (netplay cleanup, upload tmp cleanup, ZIP cache cleanup, sync session cleanup) also ship enabled. Each has an ENABLE_SCHEDULED_CLEANUP_* var to turn it off and a matching SCHEDULED_CLEANUP_*_CRON to move it. With upload tmp cleanup off, abandoned chunked uploads stay in tmp/uploads under ROMM_TMP_PATH (or the resources folder when that's unset) until you delete them. Check the env var reference for the full list.
A few tasks follow other settings instead of an ENABLE_* var:
- Scheduled audit log cleanup removes events older than
AUDIT_LOG_RETENTION_DAYS(90 by default) every day at 04:30, and doesn't run at all when that var is0, which keeps events forever. - Scheduled streaming session reaper runs every minute, but only while emulator streaming is enabled, and stops sessions whose player stopped sending heartbeats.
- Scheduled conversion cache cleanup removes expired converted downloads every day at 04:00.
- Convert library is manual only, and can only run with
ROM_CONVERTO_ENABLED=true(see Library Conversion).
Triggering a task manually
From the Administration page
Administration → Tasks lists every task with its status and a way to run it. Anyone with the tasks.run scope can fire one off, scheduled tasks included, which saves waiting for the next cron tick after a config change.
From the API
The call answers 503 when no task worker is running to pick the job up. Some tasks, such as Convert library, are single-instance: asking to run one while it's already queued or running returns 409 Conflict instead of queueing a second copy.
Library scans have their own endpoint, POST /api/tasks/scan, for clients that authenticate with a token rather than a session cookie. Its optional JSON body takes the same options as the scan socket event, and an empty body queues a quick scan of the whole library with every enabled metadata source:
POST /api/tasks/scan
Authorization: Bearer <token-with-tasks.run>
Content-Type: application/json
{"type": "quick", "platforms": [12], "apis": ["igdb", "ss"]}
The body also accepts platform_fs_slugs, roms_ids and launchbox_remote_enabled, and rejects unknown keys with 422. It answers 202 with the queued job, 409 while another scan is in flight, and 503 when no scan worker is running.
Destructive tasks
A task that deletes or replaces files in your library is flagged destructive in the task list (GET /api/tasks), and the UI asks you to type a confirmation before running it. Convert library is one, since it deletes each original once its converted copy is in place. The API doesn't ask for a confirmation, so a script that calls one runs it straight away.
Monitoring tasks
- Live: Administration → Tasks page shows every task's current status (queued, running, idle, failed).
- API:
GET /api/tasks/statusfor a JSON summary. Wire this to an uptime monitor if you want alerts. - Logs: run
docker logs rommand look forrq.workerlines.
A task that's been "running" for hours is usually a scan that hit SCAN_TIMEOUT, and the logs will say so. Tasks that fail leave a stack trace in the container logs, and the RQ failed queue retains the last few for inspection.
Tuning for small hosts
On a Raspberry Pi or NAS with 2 GB of RAM and/or a single CPU core:
- Raise the cron intervals (daily → weekly) for the nightlies
- Set
SCAN_WORKERS=1andWEB_SERVER_CONCURRENCY=1, both of which default to4 - Enable the watcher but raise
RESCAN_ON_FILESYSTEM_CHANGE_DELAYto 30+ minutes - Disable image conversion if you don't care about WebP (
ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP=false) - On a big library, set
ENABLE_SCHEDULED_BUILD_RECOMMENDATIONS=falseto skip the nightly build