Skip to content

fix(transaction): retry ERR_TRY_AGAIN commits instead of dropping them silently - #1223

Merged
kriszyp merged 1 commit into
mainfrom
kris/fix-rocks-tryagain-core
Jun 10, 2026
Merged

fix(transaction): retry ERR_TRY_AGAIN commits instead of dropping them silently#1223
kriszyp merged 1 commit into
mainfrom
kris/fix-rocks-tryagain-core

Conversation

@kriszyp

@kriszyp kriszyp commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

Under bulk-ingest bursts (notably a v4→v5 migration full-table copy into a RocksDB receiver), RocksDB returns kTryAgain (rocksdb-js code ERR_TRY_AGAIN) when a transaction's snapshot sequence falls outside the memtable conflict-check window (max_write_buffer_size_to_maintain). The commit error handler in DatabaseTransaction.ts only retried ERR_BUSY; ERR_TRY_AGAIN fell through to throw. Because the commit is driven from an unawaited onCommit().then(), that rejection became an unhandled promise rejection in the worker — logged but the write was silently dropped. Copied tables froze short of their source counts with no error surfaced anywhere.

This is the data-loss mechanism behind harper-pro#308, reproduced deterministically twice in our internal migration test bench (the internal migration-bench repro).

Change

One clause: treat ERR_TRY_AGAIN like ERR_BUSY in the commit retry — retry with the existing backoff, and after MAX_RETRIES throw a ServerError (loud) rather than losing the write. Both are transient, retryable conflict conditions. Reuses the already-exercised ERR_BUSY retry/backoff path; no new control flow.

What to check

  • resources/DatabaseTransaction.ts — the retry condition + comment.
  • The ERR_TRY_AGAIN code string is confirmed against rocksdb-js (src/binding/napi/helpers.cpp:264/300, kTryAgain → "ERR_TRY_AGAIN").
  • Note: rocksdb-js was already bumped to ^2.0.0 (retuned memtable defaults — maxWriteBufferSizeToMaintain: -1, dbWriteBufferSize: 0) which reduces the frequency of this conflict; this PR handles the residual transient occurrences so they retry instead of silently dropping. The two are complementary.

Validation

Core tsc build clean. End-to-end acceptance is the internal migration-bench repro re-run (it deterministically reproduced the silent drop; per-table count parity is the signal). A focused unit test for this internal retry path needs significant transaction-harness mocking and mirrors the already-tested ERR_BUSY branch — happy to add one if reviewers want it.

🤖 Generated with Claude Opus 4.7.

…m silently

RocksDB returns kTryAgain (rocksdb-js code ERR_TRY_AGAIN) when a transaction's
snapshot sequence falls outside the memtable conflict-check window
(max_write_buffer_size_to_maintain). This happens under bulk-ingest bursts —
e.g. a v4→v5 migration full-table copy into a RocksDB receiver. The commit
error handler only retried ERR_BUSY; ERR_TRY_AGAIN fell through to `throw`,
and because the commit is driven from an unawaited onCommit().then() the
rejection became an unhandled promise rejection in the worker — logged but the
write was silently dropped, so copied tables froze short of their source counts
with no error surfaced (harper-pro#308).

Treat ERR_TRY_AGAIN like ERR_BUSY: retry with the existing backoff and, after
MAX_RETRIES, throw a ServerError (loud) rather than losing the write. Both are
transient, retryable conflict conditions.

Refs harper-pro#308.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@claude

claude Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

kriszyp added a commit to HarperFast/harper-pro that referenced this pull request Jun 10, 2026
Pulls in core fix (HarperFast/harper#1223): the RocksDB receiver was silently
dropping records during bulk full-table copy because ERR_TRY_AGAIN
(memtable conflict-check window overflow under bulk ingest) fell through the
commit retry as an unhandled rejection. Now retried like ERR_BUSY.

Refs #308.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kriszyp
kriszyp merged commit ca69f10 into main Jun 10, 2026
37 checks passed
@kriszyp
kriszyp deleted the kris/fix-rocks-tryagain-core branch June 10, 2026 22:09
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.

3 participants