Skip to content

perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis#1399

Open
scottbuscemi wants to merge 5 commits into
mainfrom
perf/taxonomy-defs-isolate-cache
Open

perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis#1399
scottbuscemi wants to merge 5 commits into
mainfrom
perf/taxonomy-defs-isolate-cache

Conversation

@scottbuscemi

@scottbuscemi scottbuscemi commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

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 (via getTaxonomyDefsgetCollectionTaxonomyNames), 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 globalThis Symbol holder (the same two-tier pattern as settings/index.ts and 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 on globalThis behind Symbol keys, matching the existing SETUP_VERIFIED_KEY / request-context / request-cache singletons.

No schema changes, no public API changes, fully backwards compatible.

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8

Screenshots / test output

Targeted unit tests (tests/unit/taxonomies/defs-cache.test.ts):

 Test Files  1 passed (1)
      Tests  4 passed (4)

pnpm lint:json → 0 diagnostics. pnpm typecheck passes 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.

…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-bot

changeset-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 42b3183

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

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

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 42b3183 Jun 22 2026, 04:53 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 42b3183 Jun 22 2026, 04:52 PM

@pkg-pr-new

pkg-pr-new Bot commented Jun 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1399

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1399

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1399

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1399

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1399

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1399

emdash

npm i https://pkg.pr.new/emdash@1399

create-emdash

npm i https://pkg.pr.new/create-emdash@1399

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1399

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1399

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1399

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1399

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1399

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1399

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1399

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1399

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1399

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1399

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1399

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1399

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1399

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1399

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1399

commit: 42b3183

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 42b3183 Jun 22 2026, 04:52 PM

@github-actions github-actions Bot added the query-count changed PR diff modifies query-count snapshot files label Jun 10, 2026
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Query-count snapshot changes

30 routes changed, total Δ -30 queries.

SQLite

Route Before After Δ
GET / (cold) 11 10 -1
GET / (warm) 11 10 -1
GET /category/development (cold) 15 14 -1
GET /category/development (warm) 14 13 -1
GET /contributors (cold) 11 10 -1
GET /contributors (warm) 11 10 -1
GET /contributors-naive (cold) 18 17 -1
GET /contributors-naive (warm) 18 17 -1
GET /pages/about (cold) 10 9 -1
GET /pages/about (warm) 10 9 -1
GET /posts (cold) 11 10 -1
GET /posts (warm) 11 10 -1
GET /posts/building-for-the-long-term (cold) 24 23 -1
GET /posts/building-for-the-long-term (warm) 24 23 -1
GET /rss.xml (cold) 5 4 -1
GET /rss.xml (warm) 5 4 -1
GET /search (cold) 12 11 -1
GET /search (warm) 12 11 -1
GET /tag/webdev (cold) 14 13 -1
GET /tag/webdev (warm) 14 13 -1

D1

Route Before After Δ
GET / (warm) 11 10 -1
GET /category/development (warm) 14 13 -1
GET /contributors (warm) 11 10 -1
GET /contributors-naive (warm) 18 17 -1
GET /pages/about (warm) 10 9 -1
GET /posts (warm) 11 10 -1
GET /posts/building-for-the-long-term (warm) 24 23 -1
GET /rss.xml (warm) 5 4 -1
GET /search (warm) 12 11 -1
GET /tag/webdev (warm) 14 13 -1

Comparing snapshot files between base and head. Updated automatically on each push.

@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@ascorbic ascorbic marked this pull request as ready for review June 22, 2026 16:40
@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Jun 22, 2026
ascorbic added 2 commits June 22, 2026 17:46
…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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core cla: signed needs-rebase overlap query-count changed PR diff modifies query-count snapshot files review/needs-review No maintainer or bot review yet size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants