perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis#1399
perf(core): cache taxonomy defs per-isolate; move runtime/db singletons to globalThis#1399scottbuscemi wants to merge 5 commits into
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: 42b3183 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 | 42b3183 | Jun 22 2026, 04:53 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 42b3183 | Jun 22 2026, 04:52 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 | 42b3183 | Jun 22 2026, 04:52 PM |
Query-count snapshot changes30 routes changed, total Δ -30 queries. SQLite
D1
Comparing snapshot files between base and head. Updated automatically on each push. |
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).
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.