Make prerender more reliable for query fields#4067
Conversation
…and any downstream promises form the search results rendering) to finish before taking prerender snapshot
…lightcardloads-to-wait-for-rendering-to-be
…-doesnt-capture-relationships-in-non-isolated
…-doesnt-capture-relationships-in-non-isolated
There was a problem hiding this comment.
Pull request overview
This pull request enhances prerender reliability for query-backed UIs by addressing timing, authentication, and recovery gaps throughout the prerender pipeline. The changes ensure that query-driven and nested relationship content (such as hero mini-cards) is fully loaded before prerender is marked ready, that fallback federated-search calls execute with correct auth/realm context, and that timeout/retry behavior is aligned across all prerender layers.
Changes:
- Centralized and increased prerender timeout configuration (90s render, 150s request with overhead)
- Implemented multi-pass render settle logic with load generation tracking to capture nested query-backed relationships
- Added realm-aware authentication for federated search fallback queries
- Enhanced eviction logic to detect and recover from unhandled promise rejections
- Enriched metadata propagation (realmURL, lastModified) from response headers to support query field fallback
- Improved relationship deserialization to handle both array and relationship object formats
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/realm-server/prerender/prerender-constants.ts | New centralized timeout configuration with env var parsing and defaults (90s render, 60s overhead) |
| packages/realm-server/prerender/utils.ts | Updated to use centralized timeout constants |
| packages/realm-server/prerender/remote-prerenderer.ts | Updated to use centralized timeout resolution |
| packages/realm-server/prerender/manager-app.ts | Updated to use centralized timeout resolution |
| packages/realm-server/prerender/render-runner.ts | Added eviction logic for promise rejection errors (status >= 500 with "reject"/"rsvp" in message) |
| packages/runtime-common/document.ts | Enriched document metadata with realmURL and lastModified from response headers |
| packages/host/app/services/store.ts | Added realmURL metadata for source-mode loads, exposed loadGeneration for settle tracking, switched to maybeAuthedFetchForRealms |
| packages/host/app/services/realm-server.ts | Added maybeAuthedFetchForRealms method with realm-specific token selection from localStorage |
| packages/base/query-field-support.ts | Enhanced fallback search triggering to detect unhydrated relationship targets |
| packages/base/card-api.gts | Updated linksTo/linksToMany deserialization to use resourceId from data.id as fallback reference, handle relationship objects in linksToMany |
| packages/host/app/routes/render.ts | Implemented multi-pass settle logic (20 passes max, 2 stable required) with loadGeneration tracking |
| packages/host/app/routes/module.ts | Restructured to wrap all module loading work in single authGuard.race call for consistent auth error handling |
| packages/host/app/services/render-service.ts | Added multi-pass async rendering (3 passes) to allow nested query work to complete |
| packages/host/app/lib/gc-card-store.ts | Exposed loadGeneration getter for render settle tracking |
| packages/realm-server/tests/prerendering-test.ts | Added comprehensive tests for public/private realm query fallback auth, updated templates with hero-mini-card structure, added indexing await |
| packages/realm-server/tests/helpers/prerender-page-patches.ts | Added installSearchRequestObserverPatch for verifying auth headers on federated search requests |
| packages/realm-server/scripts/start-all.sh | Increased WAIT_ON_TIMEOUT from 1200s to 2000s (~33 minutes) to accommodate longer prerender operations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Preview deployments |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23c5b46a45
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| timeoutMessage?: string; | ||
| } | ||
|
|
||
| export async function waitForLoadedImage( |
There was a problem hiding this comment.
this was to fix flaky image tests
| // links.self is used to tell the consumer of this payload how to get the resource via HTTP. | ||
| // data.id is used to tell the consumer how to find the resource in the included bucket. | ||
| // Prefer data.id for resourceFrom(), and fall back to links.self when data.id is missing | ||
| // (the array-style linksToMany format omits data.id). |
There was a problem hiding this comment.
I see that you only moved this comment, but it seems like a bug if only linksToMany omits data.id
There was a problem hiding this comment.
I'm not sure that is the case anymore though (i think AI moved the comment to be consistent with the declaration of resourceId), but this comment is actually ancient. probably we can remove this note in the comment.
This change set improves prerender reliability for query-backed UIs by closing timing/auth/recovery gaps from card/module hydration through render-settle capture. It ensures query-driven and nested relationship content (for example hero mini-cards) is loaded before prerender is marked ready, ensures fallback federated-search calls execute with the correct auth/realm context, and aligns timeout/retry behavior across prerender layers. It also hardens failure recovery by treating unhandled rejection-style render failures as eviction-worthy so pooled pages recover cleanly. Tests were expanded and split to reproduce delayed-query/nested-load conditions and private/public fallback-search auth paths, validating that captured HTML/search docs now include expected dynamic content.
Here is a prerender of the homepage index.json isolated format from this branch:
Here is the isolated html for the homepage index.json, which includes the hero-mini-cards in the captured HTML: