perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis - #1399
Merged
Merged
Conversation
…ns to globalThis Cut per-render D1 round trips on public pages by caching taxonomy definitions across the worker isolate, and harden the runtime/DB singletons against bundler module duplication. - getTaxonomyDefs (query #12, hit on every render that hydrates entry terms) now has a two-tier cache: per-request + per-isolate via a globalThis Symbol holder keyed by locale, invalidated in-memory by every def write (handleTaxonomyCreate, seed). Isolated DBs bypass it. - runtimeInstance/dbCache/dbInitPromise moved onto globalThis behind Symbol keys so Vite SSR chunk duplication can't spawn duplicate caches that re-run cold-start migrations/bootstrap reads. No schema or public-API changes. Cold-start db.batch() batching deferred to a follow-up.
🦋 Changeset detectedLatest commit: 9b1ba42 The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | c830d74 | Jul 01 2026, 03:01 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 9b1ba42 | Jul 01 2026, 03:12 PM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 9b1ba42 | Jul 01 2026, 03:13 PM |
Contributor
Overlapping PRsThis PR modifies files that are also changed by other open PRs: This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
…olate-cache # Conflicts: # packages/core/src/astro/middleware.ts # packages/core/src/emdash-runtime.ts # scripts/query-counts.snapshot.d1.json # scripts/query-counts.snapshot.sqlite.json
…ixed harness The pre-merge snapshots were measured with the old query-counts harness that missed queries issued during streaming (fixed in #1580). Regenerated against the fixed harness so the numbers reflect reality: the per-isolate taxonomy-defs cache removes the repeated _emdash_taxonomy_defs read on every public render (-1 query per route).
This was referenced Jun 24, 2026
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-do | 9b1ba42 | Jul 01 2026, 03:12 PM |
Merged
marcusbellamyshaw-cell
pushed a commit
to Emdash-Bug-Testing/emdash
that referenced
this pull request
Jul 22, 2026
…ns to globalThis (emdash-cms#1399) * perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis Cut per-render D1 round trips on public pages by caching taxonomy definitions across the worker isolate, and harden the runtime/DB singletons against bundler module duplication. - getTaxonomyDefs (query emdash-cms#12, hit on every render that hydrates entry terms) now has a two-tier cache: per-request + per-isolate via a globalThis Symbol holder keyed by locale, invalidated in-memory by every def write (handleTaxonomyCreate, seed). Isolated DBs bypass it. - runtimeInstance/dbCache/dbInitPromise moved onto globalThis behind Symbol keys so Vite SSR chunk duplication can't spawn duplicate caches that re-run cold-start migrations/bootstrap reads. No schema or public-API changes. Cold-start db.batch() batching deferred to a follow-up. * chore: format changeset * ci: update query-count snapshots * chore: regenerate query-count snapshots with taxonomy-defs cache on fixed harness The pre-merge snapshots were measured with the old query-counts harness that missed queries issued during streaming (fixed in emdash-cms#1580). Regenerated against the fixed harness so the numbers reflect reality: the per-isolate taxonomy-defs cache removes the repeated _emdash_taxonomy_defs read on every public render (-1 query per route). * ci: update query-count snapshots --------- Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com> Co-authored-by: Matt Kane <mkane@cloudflare.com>
marcusbellamyshaw-cell
pushed a commit
to Emdash-Bug-Testing/emdash
that referenced
this pull request
Jul 22, 2026
…ns to globalThis (emdash-cms#1399) * perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis Cut per-render D1 round trips on public pages by caching taxonomy definitions across the worker isolate, and harden the runtime/DB singletons against bundler module duplication. - getTaxonomyDefs (query emdash-cms#12, hit on every render that hydrates entry terms) now has a two-tier cache: per-request + per-isolate via a globalThis Symbol holder keyed by locale, invalidated in-memory by every def write (handleTaxonomyCreate, seed). Isolated DBs bypass it. - runtimeInstance/dbCache/dbInitPromise moved onto globalThis behind Symbol keys so Vite SSR chunk duplication can't spawn duplicate caches that re-run cold-start migrations/bootstrap reads. No schema or public-API changes. Cold-start db.batch() batching deferred to a follow-up. * chore: format changeset * ci: update query-count snapshots * chore: regenerate query-count snapshots with taxonomy-defs cache on fixed harness The pre-merge snapshots were measured with the old query-counts harness that missed queries issued during streaming (fixed in emdash-cms#1580). Regenerated against the fixed harness so the numbers reflect reality: the per-isolate taxonomy-defs cache removes the repeated _emdash_taxonomy_defs read on every public render (-1 query per route). * ci: update query-count snapshots --------- Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com> Co-authored-by: Matt Kane <mkane@cloudflare.com>
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.
What does this PR do?
Cuts per-render D1 round trips on public pages by caching taxonomy definitions across the worker isolate, and hardens the runtime/DB singletons against bundler module duplication.
Every public render that hydrates entry terms read
SELECT * FROM _emdash_taxonomy_defs(viagetTaxonomyDefs→getCollectionTaxonomyNames), which only had per-request caching. On Cloudflare D1, where the worker colo is often far from the database primary, each query is a ~40ms cross-region round trip, so this fired on every warm request for no benefit — taxonomy definitions change extremely rarely (created via the admin API or a seed; there is no edit/delete-def path).They're now cached per-isolate behind a
globalThisSymbol holder (the same two-tier pattern assettings/index.tsand the byline field-defs cache), keyed by resolved locale and invalidated in-memory by every def write (handleTaxonomyCreate, seed application). Invalidation is in-memory rather than a persisted version probe on purpose: a per-request version read would merely replace the query being removed, yielding no net saving on warm isolates. Isolated databases (playground / DO preview) bypass the cache.Separately, the cached runtime instance, the DB-instance cache, and the in-flight DB-init promise (
astro/middleware.ts,emdash-runtime.ts) were plain module-scoped variables. Under Vite SSR chunk duplication those can become multiple independent copies, letting cold-start migrations and bootstrap reads re-run on requests that should have hit the warm cache. They now live onglobalThisbehind Symbol keys, matching the existingSETUP_VERIFIED_KEY/ request-context / request-cache singletons.No schema changes, no public API changes, fully backwards compatible.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
Targeted unit tests (
tests/unit/taxonomies/defs-cache.test.ts):pnpm lint:json→ 0 diagnostics.pnpm typecheckpasses across all packages.Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
perf/taxonomy-defs-isolate-cache. Updated automatically when the playground redeploys.