Repository navigation
⚡ Rule pages - Do not render a page again when its content did not change - #2805
Open
bradystroud wants to merge 2 commits into
Open
bradystroud wants to merge 2 commits into
bradystroud wants to merge 2 commits into
Conversation
13 tasks
Member
Author
|
🎬 Explainer video for this pull request (about 40 seconds, no sound): the problem, the change, and how it helps. 🤖 Generated with Claude Code pr-2805.mp4 |
…cache gives to each rule page (#2801) The cache of the giscus discussion numbers had `revalidate: 6 hours`. Next.js copies a numeric `revalidate` of `unstable_cache` to each page that calls the function. Each rule page calls it, so each rule page became stale 6 hours after a deploy. The first request after that time rendered the page at run time. A run time render gives the page the 60 second period of the layout query. From then on, each request for a stale rule page started a render that sends 17 requests to TinaCloud. The cache now has no period. The numbers are read again in each build, and when the Tina webhook revalidates a rule page. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
…validation period (#2801) The root layout sent the global settings query with `next: { revalidate: 60 }`. Each page that the server rendered at run time got a 60 second revalidation period from that request. This applies to an edited rule or category, to a path that is not a rule, and to the home, categories, search, user, archived and orphaned pages, which declare 5 minutes or 6 hours. The layout now reads the settings through `unstable_cache` with the tag `global-settings` and no period. A page changes only after a revalidation on demand, after its own period, or in a deploy. The Tina webhook route marks the tag stale when a file in `global/` changes. A fallback page that the server renders at run time now also has no period. Merge this commit after #2802, which stops the fallback for a failed Tina request. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb
bradystroud
force-pushed
the
bs/2801-rule-page-revalidate
branch
from
November 13, 2026 04:11
ce3aec4 to
9de9506
Compare
Member
Author
|
Updated to the latest `main` (9de9506).
🤖 Generated with Claude Code |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
✏️ Relates to #2801. The production server renders a rule page again on almost each request, and each render sends 17 requests to TinaCloud. After this change, the server renders a page only after a content change (Tina webhook) or in a deploy.
Problem. Two settings together put all rule pages on a 60 second revalidation cycle.
components/layout/layout.tsxsent the global settings query withnext: { revalidate: 60 }.8d96be7), and the file is the same intinacms/tina-nextjs-startertoday. Fix: add diagnostics for Rule loading failures #2705 only moved the lines.cacheDir) answers this query for almost all pages. Next.js then does not see the option. In a local build ofmain, 20 of 4,192 pages got the 60 seconds.s-maxage=60.giscusDiscussions.service.tscached the discussion numbers withrevalidate: 6 hours(fix: map giscus comments by discussion number instead of search #2776, in production from 12 Nov). Next.js copies a numericrevalidateofunstable_cacheto each page that calls the function. Each rule page calls it.s-maxage=31536000. It gets the 60 seconds when the webhook revalidates it.s-maxage=60.global/index.jsonchanged 2 times in 12 months.Changes
lib/services/github/giscusDiscussions.service.ts: the cache has no period. The numbers are read again in each build, and when the webhook revalidates a rule page. That render does not use a cache entry that is older than the revalidation (measured: 2 GitHub requests in that render).lib/services/global/globalSettings.service.tsreads the global settings throughunstable_cachewith the tagglobal-settingsand no period.unstable_cacheand not fetch options, because the Tina disk cache hides fetch options from Next.js in a build. Withunstable_cache, 4,180 of 4,180 pages that have the layout carry the tag.unstable_cachestores only a result. A throttled TinaCloud response (HTTP 200 with an error) is thus not stored, which was possible with the fetch option.components/layout/layout.tsxuses that function.app/api/revalidate/route.tsmarks the tag stale when a file inglobal/changes. It uses"max"(stale while revalidate), because the tag is on each page. A visitor gets the current page, and Next.js renders the new one in the background.Checks
Local production builds with the local Tina server (
tinacms build --local, client with the disk cache as in CI), 4,192 pages, standalone server. A local stub answers the giscus lookup, so the lookup works as in CI.2741dc4)s-maxage=31536000)STALE, 17 Tina requests, thens-maxage=60HIT, 0 requestsSTALE, 17 Tina requestsHIT, 0 requestss-maxage=60s-maxage=31536000staysSTALEone time, then the new settings/search,/user,/archived,/orphanedafter a run time renders-maxage=60s-maxage=300/and/categoriesafter a run time renders-maxage=60s-maxage=21600cache-control: s-maxage=60, stale-while-revalidate=31535940.s-maxage=60andSTALE. The home, categories, search, user and archived pages hads-maxage=60.main, changed the page header tos-maxage=137.biome lintandtsc --noEmitpass.tina-lock.jsonhas no diff.Options for the period (product decision)
next: { revalidate: 3600 }on the query).unstable_cache).What changes for editors and visitors (option B)
homepage/index.json), the title of a rule in a category list or in a related rule card./and/categories, 5 minutes for search, user, archived and orphaned)./app). After a container restart, an edited page shows its build-time HTML again until the next webhook for that page or the next deploy. Before, the 6 hour and 60 second periods repaired that. The daily 06:00 UTC deploy limits the window to about 24 hours. The alternative is a long period, for example 24 hours, on the rule pages.Effect of commit 1 on the comments (giscus)
The stated intent in
giscusDiscussions.service.tswas: "the number refreshes on each deploy, or when a rule edit revalidates its page". Commit 1 makes the code do that.discussionNumber: null.components/Discussion.tsxthen usesmapping="specific"with the rule GUID, which is the behavior before fix: map giscus comments by discussion number instead of search #2776. The comments show when the GitHub discussion search works. A rule gets its discussion with its first comment, so this applies to a rule that got its first comment after the last deploy.Merge order
main, a failed Tina request at run time gives a NOT FOUND fallback page. With commit 2 that page has no period. 🐛 Rule pages - Retry throttled Tina requests and render the fallback only for a missing record #2802 stops the fallback for a failed request.app/[filename]/page.tsx, which 🐛 Rule pages - Retry throttled Tina requests and render the fallback only for a missing record #2802 owns.Not in this PR
USER nextjsbeforeCOPY --from=builderwith no--chown, so/appbelongs to root. The server keeps a re-rendered page only in memory (50 MB). An edited page that is not in memory renders again on each request until the next deploy.--chown=nextjs:nodejson the threeCOPY --from=builderlines fixes it (tested in a small image that has the same commands)./app/tina/__generated__/.cache, the Tina client answers each query from disk, and an edit does not show after the webhook (measured in the local build). With--chownon theCOPYlines,/appitself stays owned by root and the folder cannot be created (tested in the small image). This holds only while the standalone output has notinafolder.main, a fallback page from a failed Tina request is then written to disk. Make this change after 🐛 Rule pages - Retry throttled Tina requests and render the fallback only for a missing record #2802.getFullRelativePathFromFilename(app/[filename]/page.tsx:19-56) reads all 6 pages oftopCategoryWithIndexQueryfor a path that is not a category, and the page andgenerateMetadataeach call it. 🐛 Rule pages - Retry throttled Tina requests and render the fallback only for a missing record #2802 makes it 6.category-uri-title-map.jsoncannot replace it as it is: its keys are theurifield and not the file name, it has no top category folder, and it has 238 of the 239 categories./latest-rulesreadssearchParams, so it is dynamic and itsrevalidate = 300has no effect.Screenshot (optional)
✏️ Not applicable. The pages do not change.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UTtNDpWnuaUUQ2winSSgMb