fix: wrap concurrent operations in transactions for atomicity#495
Conversation
- Content update: move _rev optimistic concurrency check inside transaction so read-then-write is atomic (H1) - Menu reorder: wrap sequential item updates in withTransaction to prevent partial reorder on crash (M4) - Byline delete: replace db.transaction() with withTransaction() for D1 compatibility (M7) - Seed content: wrap each entry creation/update + bylines + taxonomies in a per-entry transaction (M17)
Addresses adversarial review feedback: - Hoist findById to serve both _rev check and old slug capture (was called twice) - Remove unused HTTP status from thrown apiError objects (status is derived from error code downstream)
🦋 Changeset detectedLatest commit: 4cc3cb7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 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 |
emdash-playground | 4cc3cb7 | Apr 12 2026, 06:53 PM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@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-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
Pull request overview
Improves write-atomicity across core operations by standardizing on withTransaction() for multi-step DB updates, aiming to prevent partially-applied changes during concurrent writes or mid-operation crashes.
Changes:
- Wrap content update flow (including
_revoptimistic concurrency check) in a transaction and dedupe redundant reads. - Make menu item reorder updates atomic by performing the full reorder + re-read inside
withTransaction(). - Use
withTransaction()for byline deletion (and seed content writes) to improve D1 compatibility and reduce partial-write risk.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/seed/apply.ts | Wrap per-entry content create/update + bylines + taxonomies in withTransaction() for atomic seed application. |
| packages/core/src/database/repositories/byline.ts | Use withTransaction() for byline delete to improve atomicity and D1 compatibility. |
| packages/core/src/api/handlers/menus.ts | Wrap reorder loop + fetch in withTransaction() to avoid partial reorders. |
| packages/core/src/api/handlers/content.ts | Move _rev check into the transactional update path and avoid duplicate findById calls. |
| .changeset/poor-feet-watch.md | Adds a patch changeset documenting the atomicity fixes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-cms#495) * fix: wrap concurrent operations in transactions for atomicity - Content update: move _rev optimistic concurrency check inside transaction so read-then-write is atomic (H1) - Menu reorder: wrap sequential item updates in withTransaction to prevent partial reorder on crash (M4) - Byline delete: replace db.transaction() with withTransaction() for D1 compatibility (M7) - Seed content: wrap each entry creation/update + bylines + taxonomies in a per-entry transaction (M17) * fix: deduplicate findById in content update, remove dead status field Addresses adversarial review feedback: - Hoist findById to serve both _rev check and old slug capture (was called twice) - Remove unused HTTP status from thrown apiError objects (status is derived from error code downstream) * chore: add changeset for transaction correctness fixes * style: format --------- Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
What does this PR do?
Fixes four atomicity gaps identified in the code quality review (findings H1, M4, M7, M17).
_revoptimistic concurrency check inside the transaction so the read-then-write is atomic. A concurrent write between the rev check and update can no longer succeed. Also deduplicated a redundantfindByIdcall when both_revandslugare provided.withTransaction()to prevent partial reorder if a crash occurs mid-loop.db.transaction().execute()withwithTransaction()for D1 compatibility (D1 doesn't support native transactions;withTransactionhandles the fallback).Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure