When a server render is slow enough that a prefetch exceeds SSR_PREFETCH_TIMEOUT_MS (10s in apps/web/src/core/react-query/query-helpers.ts), withSsrTimeout resolves undefined and prefetchQuery swallows it. The page then renders with no entries, and because the route still emits s-maxage=300, that entry-less document is cached and served to everyone for the next five minutes.
Observed on a profile page: the same URL renders its full list of entries in well under a second in one environment and returns a shell with zero entries in another, repeatably, until the cache expires.
Degrading to a client-side fetch is the right behaviour. Caching the degraded result is not: one slow render becomes five minutes of empty pages for every visitor, and for a crawler it is an empty page with no content at all.
Worth considering:
- when a prefetch times out, mark the response so it is not stored (private or
s-maxage=0), letting the next request try again;
- or serve the previous good document (stale-while-revalidate already allows this) rather than replacing it with an empty one;
- and count timeouts, since today they are silent by design and nothing surfaces that a page was served empty.
Related: reducing what a render has to fetch and retain shortens the window where this can happen at all. The feed slimming in #1545 is one step; the audit follow-ups in this milestone are others.
When a server render is slow enough that a prefetch exceeds
SSR_PREFETCH_TIMEOUT_MS(10s inapps/web/src/core/react-query/query-helpers.ts),withSsrTimeoutresolvesundefinedandprefetchQueryswallows it. The page then renders with no entries, and because the route still emitss-maxage=300, that entry-less document is cached and served to everyone for the next five minutes.Observed on a profile page: the same URL renders its full list of entries in well under a second in one environment and returns a shell with zero entries in another, repeatably, until the cache expires.
Degrading to a client-side fetch is the right behaviour. Caching the degraded result is not: one slow render becomes five minutes of empty pages for every visitor, and for a crawler it is an empty page with no content at all.
Worth considering:
s-maxage=0), letting the next request try again;Related: reducing what a render has to fetch and retain shortens the window where this can happen at all. The feed slimming in #1545 is one step; the audit follow-ups in this milestone are others.