Skip to content

fix(cloudflare): use timestamp-based ids to handle table recreation - #2190

Merged
dinwwwh merged 4 commits into
mainfrom
claude/brave-newton-hkj1wr
Oct 6, 2026
Merged

dinwwwh merged 4 commits into
mainfrom
claude/brave-newton-hkj1wr

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Oct 6, 2026

Copy link
Copy Markdown
Member

Summary

Fixes an issue where resuming from a message id after idle cleanup or schema reset could skip newer events. The problem occurs because SQLite's AUTOINCREMENT sequence restarts when a table is recreated, causing new ids to be lower than ids issued before the cleanup.

Changes

  • Use timestamp-based IDs: Initialize the sqlite_sequence to Date.now() * 1000 (microseconds) when creating the events table, ensuring new ids always exceed previously issued ids
  • Update tests to handle dynamic IDs:
    • Changed hardcoded id assertions (e.g., '1', '2') to use expect.any(String) or compute relative to the first received id
    • Added test case resumes events stored after idle cleanup for an id issued before it to verify the fix works correctly
    • Added setup code in resumes messages in numeric id order test to reset the sequence and test the digit boundary scenario

Implementation Details

The fix ensures that when a durable object's storage is cleaned up and the events table is recreated, the AUTOINCREMENT sequence starts at a microsecond timestamp rather than 1. This guarantees that any new events published after cleanup will have ids greater than ids issued before cleanup, making resume queries (WHERE id > ?) work correctly.

https://claude.ai/code/session_017T4x44m5ATzLkRn6JNgLr2

claude added 4 commits October 6, 2026 02:09
… recreated

The idle alarm's deleteAll() and resetSchema's DROP TABLE reset the
AUTOINCREMENT sequence, so new events got ids starting at 1 again. Replay
uses `WHERE id > ?`, so a subscriber resuming with an id issued before the
reset silently skipped every newer event stored since.

Seed the sequence with the current time in microseconds whenever the
table is created, so ids issued after a reset stay above earlier ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017T4x44m5ATzLkRn6JNgLr2
The previous fix seeded the id sequence with the current time, which
only kept new ids above old ones while the old table averaged fewer than
1,000 events per millisecond.

Give each events table a generation instead, stored in a meta table and
changed whenever the table is recreated, and issue `<generation>-<sequence>`
ids. On resume, an id from another generation replays every stored event,
however the sequences compare, so no assumption about the event rate is
left. Tables created before this change keep issuing plain ids, so ids
already held by subscribers keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017T4x44m5ATzLkRn6JNgLr2
- Issue `<generation>-<sequence>` ids from every table, including tables
  created before generations existed (`0-<sequence>`). Plain ids already
  held by subscribers still parse as generation `0`, so one id format
  remains.
- Declare the meta table `WITHOUT ROWID`, so its primary key needs no
  hidden index and each write touches one B-tree instead of two.
- Tighten test assertions loosened by the earlier time-seed approach and
  drop redundant test steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017T4x44m5ATzLkRn6JNgLr2
Revert the generation-prefixed ids (e18a7f2, b7a396c) and keep the
time-seeded AUTOINCREMENT sequence from 4bd6e5b, so resume ids stay plain
integers compared with `WHERE id > ?` and no extra storage is needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017T4x44m5ATzLkRn6JNgLr2
@cloudflare-workers-and-pages

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 Preview URL Updated (UTC)
✅ Deployment successful!
View logs
orpc 94c99db Commit Preview URL

Branch Preview URL
Oct 06 2026, 08:18 AM

@codecov

codecov Bot commented Oct 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 28 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing claude/brave-newton-hkj1wr (94c99db) with main (769916d)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@pkg-pr-new

pkg-pr-new Bot commented Oct 6, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2190

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2190

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2190

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2190

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2190

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2190

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@2190

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2190

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2190

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2190

@orpc/experimental-lock

npm i https://pkg.pr.new/@orpc/experimental-lock@2190

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@2190

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2190

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2190

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2190

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2190

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2190

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2190

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2190

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2190

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2190

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2190

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2190

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2190

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2190

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2190

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2190

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2190

commit: 94c99db

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — reviewed the full PR head (all four commits, final state), including a local test run of both publisher suites and type:check.

  • Time-seeded AUTOINCREMENT sequence — when the events table is actually created (rowsWritten > 0), ensureSchemaAndCleanup now seeds sqlite_sequence with Date.now() * 1000 microseconds, so ids issued after recreation are always greater than ids issued before it. Plain integers are preserved, so the existing WHERE id > ? numeric comparison and the TEXT-cast read path are untouched.
  • Regression test — resumes events stored after idle cleanup for an id issued before it fails without the seeding (replays 0 instead of 2) and passes with it, so it genuinely pins the reported bug.
  • Test adaptations — hardcoded ids ('1', '2', '3') became expect.any(String) or computed relative to the first id, and the digit-boundary test now forces UPDATE sqlite_sequence SET seq = 0 to exercise numeric ORDER BY with 9→10.

Verified locally: pnpm --filter @orpc/cloudflare exec vitest run src/publisher-object.test.ts src/publisher.test.ts → 34 passed; type:check passes; no stale references to the reverted generation/prefix:meta approach remain.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@dinwwwh
dinwwwh merged commit 648d1b2 into main Oct 6, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants