Jobs and queues
Almost everything Frameleaf does with a new photo or video happens in the background as jobs: reading its details, making thumbnails, finding faces, indexing it for search, transcoding videos and more. Jobs wait in queues, and the server works through them as fast as its settings allow.
Where to manage jobs
Section titled “Where to manage jobs”Open Settings, then Compute & jobs to see every queue. For each one you can see how many jobs are active, waiting and failed, and which account and worker each job belongs to. You can:
- Pause and Resume a queue. Active jobs finish even when their queue is paused; it just stops taking new work. A few essential background queues can’t be paused.
- Run missing (or Scan missing) to queue only the items that haven’t been processed yet.
- Reprocess all to run the queue again for every item. For faces, Refresh faces updates results without a full reset, while Reset & reprocess clears generated face results first.
- Retry failed to put failed jobs back with their saved inputs. Read the error and fix the cause first.
- Remove failed records or Clear waiting jobs. Neither deletes any original file.
- Change each queue’s concurrency. See Concurrency below.
- Create job to start a maintenance task, such as Back up the database, the integrity checks, Generate memories, Clean up unused people or Collect library analytics.
Server-wide actions ask you to review the effect on every account before they run. Filtering the page by account changes only what you see, not what a queue command affects.
The classic Administration, then Job Queues page offers the same queues with All and Missing buttons.
The queues
Section titled “The queues”Queues are grouped as Media, Intelligence, Maintenance and System.
| Queue | What it does | Default concurrency |
|---|---|---|
| Metadata | Reads capture dates, camera details, location and embedded metadata | 5 |
| Storage organization | Moves files according to the storage template | |
| Thumbnails | Makes image previews and thumbnails | 3 |
| Playback videos | Makes compatible playback copies of original videos | 1 |
| Visual search | Indexes visual content for smart search | 2 |
| Face detection | Finds faces before they’re matched to people | 2 |
| Face recognition | Matches detected faces to people | |
| Text recognition | Extracts searchable text from images | 1 |
| Photo duplicates | Finds visually similar photos | |
| Video duplicates | Compares sampled video frames to find duplicate videos | 1 |
| Enrichment coordinator | Schedules descriptions and Locked-content analysis | 2 |
| Descriptions & tags | Describes photos and suggests tags | 2 |
| Locked-content detection | Identifies images to keep Locked | 2 |
| Pet recognition | Suggests which of your pets appear in photos | 1 |
| Media edits | Renders saved photo and video edits | 2 |
| Media health | Inspects missing or damaged files | 2 |
| Integrity checks | Checks files exist, are known and match their checksums | 1 |
| External libraries | Rescans your external libraries | 5 |
| Metadata sidecars | Finds sidecar files or syncs their metadata | 5 |
| File migration | Moves generated files into their current layout | 5 |
| Search maintenance | Maintains search records | 5 |
| Workflows | Runs your workflow actions after library events | 5 |
| Notifications | Delivers notifications and messages | 5 |
| Background tasks | Clean-up, coordination and follow-up tasks | 5 |
| Database backup | Backs up the database |
A blank concurrency means the queue has no setting of its own; some queues are fixed at one job at a time to keep operations in order.
What happens after an upload
Section titled “What happens after an upload”Each new upload sets off a chain of jobs:
- Metadata is read.
- Storage organization moves the file, if the storage template is on.
- Thumbnails are made: large, small, blurred and face thumbnails.
- Then, in parallel:
- Visual search indexing, followed by duplicate detection
- Face detection, followed by face recognition
- Text recognition
- Video transcoding, for videos
- Image enrichment: descriptions, tags and Locked-content detection
Image enrichment jobs
Section titled “Image enrichment jobs”Locked-content detection and Descriptions & tags have separate queues, so you can run them independently. For example, classify Locked content first, review the results, then fill in descriptions and tags, without changing settings in between.
- When both are on, a new upload queues one description job after its thumbnails. That job runs Locked-content detection first if there’s no saved result, then passes the result to the description model.
- When only Locked-content detection is on, uploads queue it directly.
- Backfill jobs process images that have previews, and skip deleted, hidden and Locked items. A normal run skips items that already have a result; reprocessing recalculates them, but never adds duplicate
AI description:blocks or repeated tags.
See AI descriptions and smart albums.
Nightly tasks
Section titled “Nightly tasks”Some jobs run on a schedule. Set them in Administration, then Settings, then Nightly Tasks Settings:
| Setting | What it does | Default |
|---|---|---|
| Start time | When the nightly tasks start | 00:00 |
| Database cleanup tasks | Clean up old, expired data from the database | On |
| Generate missing thumbnails | Queue items without thumbnails for thumbnail generation | On |
| Cluster new faces | Run face recognition on newly detected faces | On |
| Generate memories | Create new memories | On |
| Sync quota usage | Update each person’s storage quota usage from what they actually use | On |
Other scheduled jobs have their own settings: database backups (2:00 AM), integrity checks (3:00 AM) and external library scans (midnight).
Concurrency
Section titled “Concurrency”Concurrency is how many jobs of a kind each server worker runs at once. Higher values can finish a backlog sooner, but compete for CPU, GPU memory and disk bandwidth, and for machine learning jobs they use more video memory.
- Concurrency changes join the same Review changes draft as other settings.
- A new limit applies to the next jobs to start. Lowering it doesn’t cancel active jobs.
- Values from 1 to 1,000 are accepted.
- If you add GPUs or split work across containers, raise the machine learning concurrencies to keep them busy.
Restorations aren’t in these queues and never take a queue’s slot. See Workers and where jobs run.
Inside the server container
Section titled “Inside the server container”The immich-server container runs several workers:
| Worker | What it does |
|---|---|
api |
Answers requests from the web and the apps |
microservices |
Runs jobs: thumbnails, video encoding and most other background work |
edge |
Serves remote access and passes requests to api. It does nothing until remote access is on for a linked server |
Machine learning runs in its own container, or on other computers; see Workers and where jobs run.
Stopping the server
Section titled “Stopping the server”When the container stops (docker compose stop, an upgrade or a NAS package restart), each worker stops taking new work. Running jobs and requests get a grace period to finish. A job still running after that goes back to waiting, so it runs again as soon as the server is back. Jobs that could repeat a side effect, such as sending an email or a push notification, are marked failed instead.
| Variable | What it sets | Default |
|---|---|---|
FRAMELEAF_SHUTDOWN_GRACE_SECONDS |
How long running work gets to finish | 5 |
FRAMELEAF_SHUTDOWN_DEADLINE_SECONDS |
When the server exits, whatever is still running | 9 |
The grace period must be shorter than the deadline. Docker kills the container when its own stop timeout ends, so it must be longer than the deadline. The provided Compose files and NAS packages set stop_grace_period: 10s on the server (Unraid: --stop-timeout=10). Keep it if you write your own Compose file, and raise it if you raise the deadline.
If the server is killed or crashes, jobs that were running are picked up again about a minute after the next start.
Split the server into containers
Section titled “Split the server into containers”You can run the workers in separate containers, for example one for the web and API and one for background jobs, by choosing which workers each container runs:
| Variable | What it does |
|---|---|
FRAMELEAF_WORKERS_INCLUDE |
Run only these workers, comma-separated |
FRAMELEAF_WORKERS_EXCLUDE |
Run every worker except these |
- Copy the whole
immich-serverblock indocker-compose.ymlas a new service. In the copy, change the service and container name and remove theportssection:
immich-server: container_name: frameleaf_server ports: - 2283:2283frameleaf-microservices: container_name: frameleaf_microservices- Give each service its workers:
services: immich-server: # ... environment: FRAMELEAF_WORKERS_INCLUDE: 'api,edge'
frameleaf-microservices: # ... environment: FRAMELEAF_WORKERS_EXCLUDE: 'api'By default edge runs wherever api runs. When you name workers in FRAMELEAF_WORKERS_INCLUDE, only those run, so include edge alongside api if you use remote access. A container that excludes api doesn’t run edge unless FRAMELEAF_WORKERS_INCLUDE names it. If you run edge in a different container from api, give both containers the same FRAMELEAF_EDGE_SECRET (at least 16 characters).
To spread work across several machines, see Scaling.