GET /Persons never returns on a library with tens of thousands of people #77

Closed
opened 2026-08-04 20:20:42 +02:00 by Claude · 0 comments
Collaborator

GET /Persons never returns on a library with tens of thousands of people.

Measured against a database copied from a running Jellyfin — 55,523 items, of
which 32,488 are Person rows, 14 users. Both servers were given their own copy
of it and asked the same question:

upstream this port
GET /Persons?Limit=50&SortBy=SortName 0.21s, 200, 52 bytes no answer after 10 minutes
GET /Persons?Limit=50&SortBy=SortName&StartIndex=20000 0.2s, 200 no answer after 2 minutes

It is not blocked — the process holds a core at 90% for as long as it is left
to. So this is work being done, not a lock, and the amount of it does not look
bounded by Limit.

Two separate things are in that table.

The one that matters is the cost. Limit=50 asks for fifty rows and gets
neither fifty rows nor an answer. Whatever the by-name person listing does, it
does not stop at the page. Against the default snapshot — one Person row —
the same request is instant, which is why nothing has caught it: the fixture has
never had enough rows for the shape of the work to show.

The second is that upstream answers 52 bytes. That is an empty list, not
fifty people, so the two servers do not agree about what the route means either.
Worth settling before the cost is fixed, because "what should it return" decides
which query is the right one to make fast. Upstream's /Persons filters to
people attached to something the user can see; ours appears to consider all
32,488.

To reproduce. Any library with enough people will do; the count matters and
nothing else does.

# upstream, against its own copy
curl -s -o /dev/null -w '%{time_total}s %{http_code} %{size_download}\n' \
    -H "Authorization: MediaBrowser Token=\"$TOKEN\"" \
    'http://127.0.0.1:8096/Persons?Limit=50&SortBy=SortName'

# ours, same question
curl -s -o /dev/null -w '%{time_total}s %{http_code} %{size_download}\n' \
    -H "Authorization: MediaBrowser Token=\"$TOKEN\"" \
    'http://127.0.0.1:8097/Persons?Limit=50&SortBy=SortName'

SELECT count(*) FROM BaseItems WHERE Type LIKE '%Person' says whether a
library is big enough to show it. At 32,488 it is; at 1 it is not.

`GET /Persons` never returns on a library with tens of thousands of people. Measured against a database copied from a running Jellyfin — 55,523 items, of which 32,488 are `Person` rows, 14 users. Both servers were given their own copy of it and asked the same question: | | upstream | this port | |---|---|---| | `GET /Persons?Limit=50&SortBy=SortName` | 0.21s, 200, 52 bytes | no answer after **10 minutes** | | `GET /Persons?Limit=50&SortBy=SortName&StartIndex=20000` | 0.2s, 200 | no answer after 2 minutes | It is not blocked — the process holds a core at 90% for as long as it is left to. So this is work being done, not a lock, and the amount of it does not look bounded by `Limit`. Two separate things are in that table. **The one that matters is the cost.** `Limit=50` asks for fifty rows and gets neither fifty rows nor an answer. Whatever the by-name person listing does, it does not stop at the page. Against the `default` snapshot — one `Person` row — the same request is instant, which is why nothing has caught it: the fixture has never had enough rows for the shape of the work to show. **The second is that upstream answers 52 bytes.** That is an empty list, not fifty people, so the two servers do not agree about what the route means either. Worth settling before the cost is fixed, because "what should it return" decides which query is the right one to make fast. Upstream's `/Persons` filters to people attached to something the user can see; ours appears to consider all 32,488. **To reproduce.** Any library with enough people will do; the count matters and nothing else does. # upstream, against its own copy curl -s -o /dev/null -w '%{time_total}s %{http_code} %{size_download}\n' \ -H "Authorization: MediaBrowser Token=\"$TOKEN\"" \ 'http://127.0.0.1:8096/Persons?Limit=50&SortBy=SortName' # ours, same question curl -s -o /dev/null -w '%{time_total}s %{http_code} %{size_download}\n' \ -H "Authorization: MediaBrowser Token=\"$TOKEN\"" \ 'http://127.0.0.1:8097/Persons?Limit=50&SortBy=SortName' `SELECT count(*) FROM BaseItems WHERE Type LIKE '%Person'` says whether a library is big enough to show it. At 32,488 it is; at 1 it is not.
alex closed this issue 2026-08-04 20:57:56 +02:00
Sign in to join this conversation.
No description provided.