fix(e2e): copy every async-backfill source row on ObsessionDB - #227
Conversation
The full executeBackfill e2e finished every chunk and still saw 500 of 2000 target rows, one partition. A stale replica answers that partition's INSERT…SELECT with an empty scan, and reusing the plan id makes the next poll read that 0-row query_log line. Wait until all four partitions are visible, disable parallel replicas on the chunk read, and reissue empty chunks under a new plan id. The exact 2000-row assert stays. Co-authored-by: Marc Höffl <marc.hoeffl@gmail.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
chkit/packages/plugin-backfill/src/async-backfill.e2e.test.ts
Lines 307 to 311 in 25ee010
When SYSTEM SYNC REPLICA is denied, or the readiness samples repeatedly hit the same current replica, this stateless execution can still land on a stale replica and successfully finish a chunk with writtenRows === 0. The full-backfill case explicitly retries that outcome, but this resume case—and the analogous replayFailed case below—does not, so settledTargetRows() times out below 2,000 and the main-only ObsessionDB job can still fail intermittently. Apply the same new-plan-id empty-chunk replay logic to these paths.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
The
obsessiondbjob on9632090(#226) failedasync-backfill.e2e.test.ts:146:executeBackfillreported every chunk done, the source count was 2000, and the target had 500 (SOURCE_ROWS / 4). Resume and replay in the same file then copied all 2000 rows, so the plan already covered every partition. A stateless chunkINSERT…SELECTlanded on a replica that had not attached the other partitions; with parallel replicas on, that scan finishes successfully with 0 written rows. Reusing the plan id would also reuseexecuteBackfill's query id, so a retry would read the old 0-rowquery_logline.The harness now waits until a session can see all 2000 rows across 4 partitions (syncing replicas when
SYSTEM SYNC REPLICAis granted, and falling back onACCESS_DENIEDwithout requiringsystem.replicas), runs chunk reads withenable_parallel_replicas = 0, and reissues any chunk that finished with 0 written rows under a new plan id. The test still asserts the target count is exactly 2000.The
obsessiondbjob is main-only (if: push && main), so PR CI cannot prove the live ObsessionDB path. Single-nodeverifystill runs this e2e.Test plan
bun test src/async-backfill.test.ts src/mv-replay-visibility.test.tsasync-backfill.e2e.test.tsagainst local ClickHouse (full copy, resume, replay)obsessiondbjob onmainafter merge