perf(home): load the home screen once instead of twice per cold start
The Discover tab fanned out its whole request set twice on every cold start and replayed slow rows on a shrinking timeout ladder, so a healthy remote server produced anywhere from 4s to 15s of loading. Measured against a remote Jellyfin server with four libraries, 24 interleaved cold-start samples per side: requests 19 -> 9 payload 219 KB -> 94 KB settled 5231ms -> 2502ms median, 13222ms -> 5927ms p95 Four independent causes: - Retry policy. `Client.send` resolves on response headers, so the connect budget covers the server's think time and a slow-but-alive query raises `connectionTimeout`. Replaying it made the server re-run the query with a shorter budget than the one it just missed; the `[10s, 8s, 5s]` ladder turned an 11s answer into an empty row after 23s. Hub surfaces now get one whole-request deadline, retry only immediate connection errors, and the deadline bounds the whole call including the request still in flight. - Request shape. `/Items/Latest` groups a TV library by series, so its rows are Series folder dtos and `RecursiveItemCount`/`ChildCount` cost a DB count each, per row. Hub rows now ask for `Overview` only; watch state survives because Jellyfin derives `UserData.Played` from `UnplayedItemCount` when the count fields are absent. `/Shows/NextUp` sends `NextUpDateCutoff` to bound the server's series-key scan, and `Thumb` leaves `EnableImageTypes` since nothing reads it. `UserData` and `PremiereDate` leave the browse set: neither is an `ItemFields` member, so the server dropped them anyway. - Fan-out. Per-library hubs ran in batches of three separated by a barrier, so one slow library stalled every library behind it. A sliding window keeps the same peak concurrency without head-of-line blocking. Concurrent `fetchLibraries` calls now share one `/Views` instead of racing two identical round trips, Plex's global and music hub legs start together, and Jellyfin gets Plex's pool tuning. - Duplicate pass. `DiscoverScreen.initState` starts a load and the online-entry hook asked for a full refresh on top of it, which `CoalescedLoadCoordinator` correctly queued as a trailing pass. The hook now calls `primeRefresh`, which rides along with a load already in flight; profile switches still go through `fullRefresh`. Refs #1784
This commit is contained in:
@@ -7,13 +7,24 @@ class MediaServerTimeouts {
|
||||
|
||||
static const receive = Duration(seconds: 120);
|
||||
|
||||
/// Retry budget for home `/hubs` startup calls. These endpoints can be slow
|
||||
/// while Plex wakes idle disks, but should not block forever.
|
||||
static const homeHubAttemptTimeouts = [Duration(seconds: 10), Duration(seconds: 5), Duration(milliseconds: 2500)];
|
||||
/// Whole-request deadline for home `/hubs` startup calls. These endpoints can
|
||||
/// be slow while Plex wakes idle disks or a CDN-fronted Jellyfin runs a cold
|
||||
/// query, but should not block forever.
|
||||
///
|
||||
/// Deliberately a *single* budget rather than a retry ladder. `Client.send`
|
||||
/// resolves when response headers arrive, so this budget covers the server's
|
||||
/// think time, not just the socket connect — a slow-but-alive query trips it.
|
||||
/// Replaying that request makes the server re-run the same expensive query
|
||||
/// from scratch, so the old `[10s, 5s, 2.5s]` ladder turned an 11s answer
|
||||
/// into a 17.5s empty row (#1784). See [retryTransientMediaServerCall].
|
||||
static const homeHubDeadline = Duration(seconds: 15);
|
||||
|
||||
/// Retry budget for per-library home hub rows (`/hubs/sections/{id}`). These
|
||||
/// can be slower than the top-level home hub call on remote Plex servers.
|
||||
static const libraryHubAttemptTimeouts = [Duration(seconds: 10), Duration(seconds: 8), Duration(seconds: 5)];
|
||||
/// Whole-request deadline for per-library home hub rows
|
||||
/// (`/hubs/sections/{id}`, Jellyfin `/Items/Latest`). These can be slower
|
||||
/// than the top-level home hub call on remote servers. Same single-budget
|
||||
/// rationale as [homeHubDeadline] — it replaced `[10s, 8s, 5s]`, whose 23s
|
||||
/// worst case was the dominant cold-start stall in #1784.
|
||||
static const libraryHubDeadline = Duration(seconds: 20);
|
||||
|
||||
/// Timeout for probing a cached/preferred endpoint (used in
|
||||
/// [PlexServer.findBestWorkingConnection]).
|
||||
|
||||
Reference in New Issue
Block a user