Skip to content

fix(cache): compare tag revalidation timestamps - #2916

Open
JamesbbBriz wants to merge 10 commits into
cloudflare:mainfrom
JamesbbBriz:codex/fix-cache-tag-revalidation-timestamps
Open

fix(cache): compare tag revalidation timestamps#2916
JamesbbBriz wants to merge 10 commits into
cloudflare:mainfrom
JamesbbBriz:codex/fix-cache-tag-revalidation-timestamps

Conversation

@JamesbbBriz

@JamesbbBriz JamesbbBriz commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • record request-local tag revalidations with timestamps instead of membership only
  • capture each cache fill's causal timestamp at the producer, before user work starts, then pass it through the cache adapter unchanged
  • persist and return producer timestamps in Memory and Cloudflare KV while keeping adapter-owned writtenAt for TTL accounting
  • apply the same ordering contract to use cache, unstable_cache, tagged fetch, App/Pages ISR, Route Handlers, and metadata routes
  • discard entries only when they predate the latest matching revalidation, including fills that straddle an invalidation
  • securely forward revalidated-tag state across internal Server Action redirect dispatches without exposing protocol headers to application code
  • preserve comma-containing tags losslessly in a separate authenticated vinext JSON header while retaining the Next.js comma-delimited header for ordinary-tag rolling compatibility

This follows the behavior introduced by vercel/next.js#96726 and commit 5da1c1ae03d2ee39c27a2d6d8807c573c46b37f9.

The separate JSON tag header is a deliberate vinext protocol extension: Next.js's comma-delimited wire format cannot represent a legal tag containing a comma. New vinext peers prefer the authenticated JSON header; the standard header remains available to older peers for ordinary tags. Older peers cannot preserve comma-containing tags.

Closes #2819

Tests

  • 17-file cache/ISR/action/router matrix passed, including the required isr-cache, fetch-cache, and kv-cache-handler coverage
  • focused producer-ordering tests prove App Route and metadata timestamps are captured before user handlers run
  • vp check passed for all 26 changed product/test files
  • git diff --check passed

Adversarial coverage includes invalidation during a fill and immediately before a new fill, repeated same-tag invalidation, all three public cache APIs, App/Pages foreground and background ISR writes, Route Handlers, metadata routes, two-read Server Action dedupe, custom-handler old/new timestamps, authenticated redirect forwarding, comma-containing and JSON-looking legacy tags, protocol-header filtering, soft/hard tags, and Memory/KV strict timestamp boundaries.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

/bigbonk

@pkg-pr-new

pkg-pr-new Bot commented Aug 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2916
npm i https://pkg.pr.new/create-vinext-app@2916
npm i https://pkg.pr.new/@vinext/types@2916
npm i https://pkg.pr.new/vinext@2916

commit: c390a56

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared c390a56 against base 13e7d9c using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 142.4 KB 142.5 KB ⚫ +0.0%
Client entry size (gzip) vinext 129.7 KB 129.7 KB ⚫ +0.0%
Dev server cold start vinext 3.25 s 3.22 s ⚫ -0.9%
Production build time vinext 3.54 s 3.54 s ⚫ -0.0%
RSC entry closure size (gzip) vinext 125.5 KB 126.3 KB ⚫ +0.7%
Server bundle size (gzip) vinext 216.1 KB 217.2 KB ⚫ +0.5%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dab5b34173

ℹ️ 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".

Comment thread packages/vinext/src/shims/cache-request-state.ts
@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

/bigbonk

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

CI follow-up: fixed the integration failure by separating high-resolution mutation ordering (lastModified) from wall-clock TTL policy (writtenAt) in both Memory and KV handlers. Existing KV entries remain compatible via the lastModified fallback. Local verification: exact failed sequence 2/2, full features file 355/355, related 8-file matrix 1,903/1,903, scoped checks/diff-check, and independent Standards + blast-radius reviews pass. Waiting for CI; not requesting re-review yet.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd28c1de2

ℹ️ 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".

Comment thread packages/vinext/src/server/app-rsc-handler.ts Outdated
Comment thread packages/vinext/src/server/revalidated-tags.ts
@JamesbbBriz

JamesbbBriz commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@james-elicx I think this is ready for another look now. I fixed the latest ISR review comments, and CI is green. Thanks!

@NathanDrake2406

Copy link
Copy Markdown
Contributor

I think we should generate the timestamp and pass it through the adapter, then have it persist and return that instead

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

Updated in fe528e1. Cache producers now capture the timestamp before the fill starts and pass it through set(); Memory and KV persist and return it unchanged, while writtenAt remains adapter-owned for TTL accounting. I also carried the same boundary through App/Pages ISR, Route Handlers, metadata routes, use cache, unstable_cache, and tagged fetch, with ordering tests for both sides of an invalidation.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

@james-elicx I've incorporated Nathan's adapter feedback and fixed the one stale seed-cache assertion caught by CI. The full check suite is green on 729fdb7 now. Thanks for the patience - whenever you have time, this should be ready for another look.

@JamesbbBriz
JamesbbBriz force-pushed the codex/fix-cache-tag-revalidation-timestamps branch from 729fdb7 to 1874f69 Compare August 24, 2026 22:37
@JamesbbBriz

JamesbbBriz commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

@james-elicx, I rebased this onto current main and kept the producer-timestamp approach Nathan suggested. It is conflict-free and CI is green now. Could you take another look when you have a chance?

@JamesbbBriz
JamesbbBriz force-pushed the codex/fix-cache-tag-revalidation-timestamps branch from 1874f69 to 7fab14c Compare September 3, 2026 16:27
@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (2 conflicts resolved): import lists in shims/fetch-cache.ts and tests/app-rsc-handler.test.ts merged with the newer upstream imports (isInsideAnyCacheScope, cacheability test imports). No behavioural changes to the patch.

Verified locally: vp test run tests/isr-cache.test.ts tests/fetch-cache.test.ts tests/kv-cache-handler.test.ts tests/revalidated-tags.test.ts306 passed.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

You have a hard 10-minute workflow time limit. Review the cumulative diff at exact head 4dca1c4, prioritizing correctness, Next.js parity, split response-stage forwarding, ISR/data-cache invalidation ordering, and the merged #3187 KV tag-prime logic. Post an explicit LGTM/no-findings verdict or concise actionable findings before the deadline.

@ask-bonk

ask-bonk Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

@james-elicx Bonk workflow was cancelled.

View workflow run · To retry, trigger Bonk again.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

Hard 10-minute workflow limit. Review exact head 4dca1c4. Be verdict-first and concise: inspect only the cumulative cache invalidation timestamp and authenticated cross-stage forwarding changes, including merged #3187 KV tag-prime interaction. Post explicit LGTM/no findings or actionable correctness findings before the deadline; skip broad summaries.

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

Hard 10-minute workflow limit. Review exact head 4dca1c4. Verdict first: inspect only the cumulative cache invalidation timestamp ordering and authenticated cross-stage forwarding changes, including the merged #3187 KV tag-prime interaction. Immediately post explicit LGTM/no findings if clean, or only concise actionable correctness findings; skip all broad summary.

Comment thread packages/vinext/src/shims/cache-handler.ts Outdated
Comment thread packages/cloudflare/src/cache/kv-data-adapter.runtime.ts
Comment thread packages/cloudflare/src/cache/kv-data-adapter.runtime.ts Outdated
@ask-bonk

ask-bonk Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

3 actionable correctness findings posted inline. No additional findings.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

Hard 10-minute workflow limit. Re-review cumulative diff at exact head 77e2f98 after fixes for all three prior findings: Workers zero timeOrigin ordering, forwarded KV tag-cache priming, and non-destructive forwarded stale reads. Verdict first: post explicit LGTM/no findings or only concise actionable correctness findings before the deadline.

Comment thread packages/cloudflare/src/cache/kv-data-adapter.runtime.ts Outdated
Comment thread packages/cloudflare/src/cache/kv-data-adapter.runtime.ts Outdated
@ask-bonk

ask-bonk Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

2 actionable correctness findings posted inline.

github run

@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

Hard 10-minute workflow limit. Re-review exact head 0a445c9 after all prior findings. Focus on the new forwarded KV marker provenance: inclusive equality, preservation of stronger markers, detached-prime ordering, TTL replacement, and non-destructive later reads. Verdict first: post explicit LGTM/no findings or only concise actionable correctness findings before the deadline.

@ask-bonk

ask-bonk Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@JamesbbBriz
JamesbbBriz force-pushed the codex/fix-cache-tag-revalidation-timestamps branch from 0a445c9 to c390a56 Compare September 11, 2026 15:00
@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (13e7d9ce) — the series is now a clean 10 commits on top, with the full fix history preserved.

A few notes for review:

  • All findings from the Sep 9 review pass are addressed in-series. The three ask-bonk P1s confirmed as fixed in 77e2f982 survive the rebase as fix(cache): preserve forwarded KV invalidations, and the Codex-connector batch is covered as well: getCacheTimestamp now imports from the lightweight vinext/shims/cache-handler module instead of the public facade, the same-millisecond case is handled by the request-scoped previouslyRevalidatedTags guard ahead of the strict > comparison, and forwarded tags use a structured format with the legacy comma-split header kept only for rolling upgrades.
  • The adapter-timestamp suggestion from the earlier review is implemented as fix(cache): preserve producer timestamps through adapters — producer timestamps are generated once, persisted through the adapters, and compared on read rather than regenerated per hop.
  • Production validation: this exact cache stack has been running on a production Cloudflare Worker (a Payload 3 + D1 site) for the past two weeks with revalidate = 300 pages — ISR entries serve CDN-Cache-Control: public, max-age=300, stale-while-revalidate with CF-Cache-Status: HIT at 25–43 ms, and dynamic routes correctly stay BYPASS. Happy to share deployment details if useful.
  • Locally: vp check is clean, and the touched suites pass (kv-cache-handler 99, app-rsc-handler 266, fetch-cache 159; the full PR-touched set runs 1604/1604).

CI should be green on the Linux runners — a handful of build-spawning tests are flaky on my Windows machine, same as on main.

JamesbbBriz added a commit to JamesbbBriz/vinext that referenced this pull request Sep 11, 2026
…are#2916, rebased)

Rebased onto current upstream main. cloudflare#2910 and cloudflare#2915 already landed
upstream, so the integration branch is now upstream main plus this
change set only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cache: discard only 'use cache' entries that predate a tag revalidation (timestamp-compare, not tag membership)

3 participants