Skip to content

fix(kb): retry-with-backoff on embed_content, fixing intra-file 429 bursts - #170

Open
asachs01 wants to merge 3 commits into
mainfrom
fix/embed-content-retry-backoff
Open

fix(kb): retry-with-backoff on embed_content, fixing intra-file 429 bursts#170
asachs01 wants to merge 3 commits into
mainfrom
fix/embed-content-retry-backoff

Conversation

@asachs01

@asachs01 asachs01 commented Sep 3, 2026

Copy link
Copy Markdown

Summary

  • embed_content() had zero retry logic while generate_content() already retried transient 429/500/503 errors — a large file (e.g. an agent's MEMORY.md, ~238 chunks) embeds every chunk back-to-back with no pacing, so once the file's own chunk volume trips the shared embedding quota, every remaining chunk in that run also 429s with nothing pausing for recovery. Confirmed via isolated zero-contention reproduction and adoption's MEMORY.md failing 5 consecutive already-staggered ingest cycles (task_1788420454462_38838015).
  • Consolidated the fix into one _retry_with_backoff(fn, label=...) shared by both generate_content and embed_content, rather than shipping a second near-duplicate retry loop — caught by a /simplify review pass (reuse/simplification/efficiency/altitude, 4 parallel agents) after the first commit.
  • Merged the two retry test files into one (test_retry.py) that exercises both call shapes through a shared table, since there's now one implementation to test.

What's deliberately NOT addressed here

  • Proactive inter-chunk pacing in the ingest loops themselves — retry-after-failure treats the symptom; the tight per-chunk loop is what generates the burst. Flagged by the altitude review as the deeper fix; out of scope for this diff, tracked for follow-up.
  • backoffs=(5,15,45) is inherited from generate_content's tuning, not independently measured for embedding's burst window. Real-world validation pending against adoption's next live MEMORY.md ingest.

Test plan

  • New/consolidated fault-injection regression suite: python -m _test_clients.test_retry — 7 scenarios, 19 assertions, all pass
  • Pre-existing generate_content coverage preserved (now folded into the same suite, same assertions)
  • Confirmed the real production path end-to-end against the live Gemini API before and after the consolidation refactor
  • Live large-file ingest verification (adoption's MEMORY.md) — pending, will report back once observed

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…content

embed_content() had zero retry logic while generate_content already retries
transient 429/500/503 errors via _retry_generate_content. A large text file
(e.g. an agent's MEMORY.md) embeds every chunk back-to-back with no pacing,
so once the file's own chunk volume trips the shared embedding quota, every
remaining chunk in that run also 429s with nothing pausing for recovery —
the ingest dies partway through on every attempt, independent of any
cross-agent contention (confirmed via isolated reproduction and adoption's
MEMORY.md failing 5 consecutive staggered-schedule ingests).

Adds _retry_embed_content mirroring the existing _retry_generate_content
pattern exactly, wires embed_content() through it. Extends the
fault_injection test harness to script embed_content independently of
generate_content, with 4 new regression tests.
…ackoff

/simplify review of the prior commit found _retry_embed_content was a
near-verbatim copy of _retry_generate_content (same loop, same transient-code
classification, same backoff shape — only the wrapped call differed). Collapse
both into a single _retry_with_backoff(fn, label=...) taking a zero-arg
callable, so a third retry-needing call site only needs a lambda, not a third
copy of the loop.

Also merges test_retry_embed.py into test_retry.py: since there is now one
implementation, testing it via two near-duplicate suites (one per call shape)
re-introduced the same duplication at the test layer. test_retry.py now runs
each scenario against both a generate_content-shaped and an embed_content-
shaped call through a shared table, plus a cross-shape independence check.

Reviewed and deliberately NOT addressed here (would require changes well
outside this diff): proactive inter-chunk pacing in the ingest loops
themselves (retry-after-failure treats the symptom; the tight per-chunk loop
is what generates the burst) — flagged by /simplify's altitude pass as the
deeper fix, tracked for follow-up rather than expanding this diff's scope.
Also not changed: the backoffs=(5,15,45) default is borrowed from
generate_content's tuning, not independently measured for embedding's burst
window — real-world validation is pending against a live large-file ingest.
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: b3c44cc4-2080-425c-8dda-cc10ae4c1152

📥 Commits

Reviewing files that changed from the base of the PR and between e44bf20 and b4fc01c.

📒 Files selected for processing (3)
  • knowledge-base/scripts/_test_clients/fault_injection.py
  • knowledge-base/scripts/_test_clients/test_retry.py
  • knowledge-base/scripts/mmrag.py

Comment @coderabbitai help to get the list of available commands.

Caught by analyst's independent review of #170 (ran the test suite in an
isolated worktree rather than trusting the PR description): mmrag.py:860's
comment and fault_injection.py's module docstring still named the pre-
consolidation function. Cosmetic only, no behavior change.
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