Skip to content

Defer manifest cache delete via after()#874

Merged
ascorbic merged 1 commit intomainfrom
opencode/issue873-20260430221359
May 1, 2026
Merged

Defer manifest cache delete via after()#874
ascorbic merged 1 commit intomainfrom
opencode/issue873-20260430221359

Conversation

@ask-bonk
Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot commented Apr 30, 2026

Summary

Reproduced and fixed.

Bug confirmed. EmDashRuntime.invalidateManifest() at packages/core/src/emdash-runtime.ts:1571 started the D1 row delete as a bare unawaited promise. EmDash already has the after() helper (packages/core/src/after.ts) which routes deferred work through ctx.waitUntil under workerd, but invalidateManifest() didn't use it. On Cloudflare Workers the delete promise gets cancelled at response-teardown, so options.emdash:manifest_cache stays at the pre-mutation snapshot. The reporter is also right that the existing _manifestCacheKey check at line ~1294 doesn't include schema content (only commit + plugin versions + i18n), so stale rows pass the check on every cold isolate.

The reporter's pointer to a "second site at line ~993" is an off-by-line — line 1001 is already correctly awaited inside the cold-start init closure. Only invalidateManifest() had the bug.

Reproduction. Wrote a TDD-style failing test in packages/core/tests/unit/runtime/invalidate-manifest.test.ts that:

  • Spies on after() via vi.mock.
  • Pre-populates options.emdash:manifest_cache with a stale row.
  • Calls runtime.invalidateManifest().
  • Asserts (a) after() was invoked, and (b) after draining microtasks, the row is gone.

Confirmed it failed before the fix (expected "vi.fn()" to be called 1 times, but got 0 times) and passes after.

Fix. Replaced the fire-and-forget pattern with an after(async () => { ... }) block. The deletion now extends the worker's lifetime via waitUntil on Cloudflare and stays fire-and-forget on Node (where it works fine because the process keeps running). Comment updated to call out why this matters and points at the _manifestCacheKey schema-content gap.

Out of scope (per the issue's own note). The warm-sibling-isolate problem — _cachedManifest has no TTL or cross-isolate signal — is a separate bug class and isn't addressed here. The reporter said they'd file it separately.

Verification.

  • New test passes; tests/unit/after.test.ts still passes.
  • pnpm --filter emdash typecheck clean.
  • pnpm --silent lint:json | jq '.diagnostics | length' returns 14 — identical to baseline (all pre-existing null:null type-resolution diagnostics in unrelated packages).
  • 3048 of 3056 core tests pass; the 8 failures are all in tests/unit/astro/vite-config.test.ts and are pre-existing in this CI environment (admin's build script uses node --run, which the Node version here doesn't accept, so @emdash-cms/admin/dist/index.js is missing). Confirmed by stashing my change and reproducing.
  • Code formatted with pnpm format.

Changeset added at .changeset/issue-873-invalidate-manifest-after.md (patch bump on emdash).

Files changed:

  • packages/core/src/emdash-runtime.tsinvalidateManifest() now defers the D1 delete via after().
  • packages/core/tests/unit/runtime/invalidate-manifest.test.ts — new TDD test.
  • .changeset/issue-873-invalidate-manifest-after.md — changeset.

Closes #873

github run

Co-authored-by: ascorbic <ascorbic@users.noreply.github.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 30, 2026

🦋 Changeset detected

Latest commit: fd215ce

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

This PR includes changesets to release 13 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-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
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 30, 2026

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 fd215ce Apr 30 2026, 10:23 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 30, 2026

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-perf-coordinator fd215ce Apr 30 2026, 10:23 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 30, 2026

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 fd215ce Apr 30 2026, 10:24 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 30, 2026

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 fd215ce Apr 30 2026, 10:24 PM

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 30, 2026

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-i18n fd215ce Apr 30 2026, 10:23 PM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 30, 2026

Open in StackBlitz

@emdash-cms/admin

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

@emdash-cms/auth

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

@emdash-cms/blocks

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

@emdash-cms/cloudflare

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

emdash

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

create-emdash

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

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

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

@emdash-cms/x402

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

@emdash-cms/plugin-ai-moderation

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

@emdash-cms/plugin-atproto

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

@emdash-cms/plugin-audit-log

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

@emdash-cms/plugin-color

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

@emdash-cms/plugin-embeds

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

@emdash-cms/plugin-forms

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

@emdash-cms/plugin-webhook-notifier

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

commit: fd215ce

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a Cloudflare Workers-specific bug where EmDashRuntime.invalidateManifest() attempted to delete the persisted manifest cache row via an unawaited promise that could be canceled at response teardown, leaving options.emdash:manifest_cache stale across cold isolates.

Changes:

  • Route the persisted manifest-cache delete through after() so it is registered with ctx.waitUntil under workerd.
  • Add a unit test that asserts invalidateManifest() always defers its DB cleanup via after() and that the options row is removed.
  • Add a changeset for a patch release of emdash.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/core/src/emdash-runtime.ts Uses after(async () => ...) to perform the persisted manifest-cache delete so it survives Cloudflare Workers response teardown.
packages/core/tests/unit/runtime/invalidate-manifest.test.ts New unit test reproducing issue #873 and locking in the after()-based invalidation contract.
.changeset/issue-873-invalidate-manifest-after.md Patch changeset documenting the fix and user impact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ascorbic ascorbic merged commit d5f7c48 into main May 1, 2026
40 checks passed
@ascorbic ascorbic deleted the opencode/issue873-20260430221359 branch May 1, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

invalidateManifest() D1 cache delete is fire-and-forget on Cloudflare Workers, leaving stale persistent manifest cache indefinitely

2 participants