Skip to content

perf(runtime): commit accepted batches while the next batch executes - #61

Open
kyscott18 wants to merge 2 commits into
mainfrom
perf/pipelined-persist
Open

kyscott18 wants to merge 2 commits into
mainfrom
perf/pipelined-persist

Conversation

@kyscott18

@kyscott18 kyscott18 commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Depends on #58. This branch includes that commit. Merge #58 first; this diff then shrinks to one commit.

Summary

Persisting a batch (~1.2 ms, mostly the WAL fsync) ran inside the speculative-state lock, so execution waited on Postgres.

  • One fiber commits accepted batches in order, outside the lock. It groups all batches that queued during the previous commit into one transaction.
  • Callers still get a response only after their batch commits. A batch reaches submit only after it commits.
  • A failed commit now fails the waiting callers and does not leave them pending.

Correctness note: submit waits for the in-flight commit

simulate rewinds and then replays the journals it is given. This is correct only when those journals are the newest. Suppose batch N+1 has executed but is not yet committed (so it is not in acceptedBatchesQueue). Then rewinding and replaying batch N writes N's post-values over N+1's slots, and the simulation includes N+1's effects. So submit, under the lock, first waits for the most recent batch's commit. Because commits are ordered, that wait covers all earlier batches. The lock stops new batches from executing during the wait.

Results

Counter benchmark, open loop at 4,000/s (2 runs each): 3,180–3,250 → 3,577–3,580 mutations/s; p50 516–571 ms → 272–285 ms.
Closed-loop results do not change, as expected: those clients send the next mutation only after the commit.

Test plan

  • bun run lint, bun run typecheck, bun run test

🤖 Generated with Claude Code

RetriggerConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking request for focused commit-order tests.

Fix All in Claude CodeFindings

  1. P2 Commit ordering lacks a test ▶
Fix with agent prompt
### Issue 1
packages/typewriter/src/runtime.ts:799-801
The new wait in `submit` has no focused regression test. Existing tests do not hold a database commit open while another batch executes, so they would not catch a broken wait that makes settlement use the wrong local state.

Add a test that delays batch N's commit, lets N+1 execute, and checks that `submit` waits for both commits before simulating them. Also check that a failed commit rejects waiting public callers.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Moves accepted-batch persistence into a separate worker so the next batch can execute during a database commit.

  • Accepted batches commit while later mutations execute.
  • FIFO accepts queued mutations as soon as they arrive.

Diagram

sequenceDiagram
    participant Client
    participant Execute
    participant Persist
    participant Submit
    Client->>Execute: Send mutation
    Execute->>Persist: Queue accepted batch N
    Execute->>Execute: Execute batch N+1
    Persist->>Persist: Commit queued batches in order
    Persist-->>Client: Return accepted result
    Submit->>Submit: Hold state lock and wait for newest commit
    Persist-->>Submit: Publish batches, then signal commit
    Submit->>Submit: Simulate committed batches
    Submit->>Submit: Release lock and send transaction
Loading

Reviews (1) · Last reviewed commit: "perf(runtime): commit accepted batches w..." · Reviewed by Greptile

FIFO mode polled the received-mutation queue every 4ms, so each mutation
waited for the next tick. That wait was most of its latency, and the
loop woke 250 times per second when idle. FIFO now blocks on
Queue.takeAll and accepts everything that queued during the previous
batch. Batch mode keeps its fixed window for batchOrder. Both modes take
mutations outside the speculative-state lock.

Counter benchmark (sequential FIFO): 4.04ms -> 1.56ms average,
247 -> 641 mutations/s.
Persisting a batch (~1.2ms) ran inside the speculative-state lock, so
execution waited on Postgres. A single persist fiber now commits accepted
batches in order, outside the lock. It groups all batches that queued
during the previous commit into one transaction. Callers still get a
response only after their batch commits, and a batch reaches submit only
after it commits.

Simulate is correct only for the newest journals, so submit waits under
the lock for the in-flight commit before it reads the accepted batches.
A failed commit now fails the waiting callers instead of leaving them
pending.

Counter benchmark, open loop at 4,000/s (2 runs each):
3,180-3,250 -> 3,577-3,580 mutations/s; p50 516-571ms -> 272-285ms.
Closed-loop results do not change: those clients send the next mutation
only after the commit.
Comment on lines +799 to +801
if (lastBatchCommitted !== undefined) {
yield* Deferred.await(lastBatchCommitted);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Commit ordering lacks a test

The new wait in submit has no focused regression test. Existing tests do not hold a database commit open while another batch executes, so they would not catch a broken wait that makes settlement use the wrong local state.

Add a test that delays batch N's commit, lets N+1 execute, and checks that submit waits for both commits before simulating them. Also check that a failed commit rejects waiting public callers.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/typewriter/src/runtime.ts
Line: 799-801

Comment:
**Commit ordering lacks a test**

The new wait in `submit` has no focused regression test. Existing tests do not hold a database commit open while another batch executes, so they would not catch a broken wait that makes settlement use the wrong local state.

Add a test that delays batch N's commit, lets N+1 execute, and checks that `submit` waits for both commits before simulating them. Also check that a failed commit rejects waiting public callers.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

This branch has not been deployed

No deployments
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.

1 participant