The listener does not bind until the first scan finishes #18

Closed
opened 2026-08-02 14:27:24 +02:00 by Claude · 1 comment
Collaborator

serve() awaits scan_libraries at crates/jellyfin-server/src/main.rs:80;
the bind is at :175. Until the first scan completes there is no server at all
— not a 503, no port.

For this library that is 12 m 22 s of nothing. Upstream serves immediately and
scans behind the API.

The LibraryScanner port and tasks::Tasks already exist (main.rs:198-217),
so it is mostly moving the call behind the bind. The startup scan and a
task-triggered /Library/Refresh must then not overlap — a
tokio::sync::Semaphore(1) in Libraries, where failing to acquire is also the
honest answer for the task status.


Found by scanning /mnt/media (285 movies, 289 shows, 74 music artists —
~13 000 media files on a CIFS mount) with both this server and upstream
Jellyfin at the pinned commit, remote metadata and image fetchers disabled on
upstream so both were reading files only. Upstream was given the same mount
path so MD5(UTF-16LE(path)) agrees and rows compare directly.

`serve()` awaits `scan_libraries` at `crates/jellyfin-server/src/main.rs:80`; the bind is at `:175`. Until the first scan completes there is no server at all — not a 503, no port. For this library that is 12 m 22 s of nothing. Upstream serves immediately and scans behind the API. The `LibraryScanner` port and `tasks::Tasks` already exist (`main.rs:198-217`), so it is mostly moving the call behind the bind. The startup scan and a task-triggered `/Library/Refresh` must then not overlap — a `tokio::sync::Semaphore(1)` in `Libraries`, where failing to acquire is also the honest answer for the task status. --- Found by scanning `/mnt/media` (285 movies, 289 shows, 74 music artists — ~13 000 media files on a CIFS mount) with both this server and upstream Jellyfin at the pinned commit, remote metadata and image fetchers disabled on upstream so both were reading files only. Upstream was given the same mount path so `MD5(UTF-16LE(path))` agrees and rows compare directly.
Author
Collaborator

Fixed in a94abf3 and 3c96d5e.

Measured on the same library, from a fresh database: the port answers after
0.51 s
rather than after the scan. The scan then ran behind it for 30 m and
finished with the task reporting Completed and /Items/Counts full.

It runs as the scheduled task rather than beside one, so /ScheduledTasks
says Running while it does and a /Library/Refresh asked for meanwhile is
the one the task refuses — verified against the running server, and now under
test.

Upstream's ordering is the same: Program.cs starts the host before
RunStartupTasksAsync. Two differences worth recording, neither fixed here:

  • upstream answers 503 with Retry-After from a setup server on the port
    from the very first moment, where this server has no port for half a second
    and then answers normally with whatever the database holds. On a first run
    that is an empty library rather than a 503.
  • upstream does not scan at startup at all — a never-run task first fires an
    hour in. This server scans at startup because it has no setup wizard to
    create libraries.

The ffmpeg capability probe still runs before the bind: 1.7 s of ffmpeg -h
spawns on this machine, and a misconfigured encoding.ffmpeg still stops
startup rather than binding and failing per request as upstream does.


Review raised one thing worth writing down: a scan aborted part way leaves
items filed with no streams, and a later pass skips them because the file has
not moved. That is #28 — nothing backfills what a previous pass did not
write — and the overlap this commit introduces makes it easier to reach.

Fixed in `a94abf3` and `3c96d5e`. **Measured on the same library, from a fresh database: the port answers after 0.51 s** rather than after the scan. The scan then ran behind it for 30 m and finished with the task reporting `Completed` and `/Items/Counts` full. It runs *as* the scheduled task rather than beside one, so `/ScheduledTasks` says `Running` while it does and a `/Library/Refresh` asked for meanwhile is the one the task refuses — verified against the running server, and now under test. Upstream's ordering is the same: `Program.cs` starts the host before `RunStartupTasksAsync`. Two differences worth recording, neither fixed here: - upstream answers **503 with `Retry-After`** from a setup server on the port from the very first moment, where this server has no port for half a second and then answers normally with whatever the database holds. On a first run that is an empty library rather than a 503. - upstream does not scan at startup at all — a never-run task first fires an hour in. This server scans at startup because it has no setup wizard to create libraries. The ffmpeg capability probe still runs before the bind: 1.7 s of `ffmpeg -h` spawns on this machine, and a misconfigured `encoding.ffmpeg` still stops startup rather than binding and failing per request as upstream does. --- Review raised one thing worth writing down: a scan aborted part way leaves items filed with no streams, and a later pass skips them because the file has not moved. That is #28 — nothing backfills what a previous pass did not write — and the overlap this commit introduces makes it easier to reach.
Sign in to join this conversation.
No description provided.