Stop large embedding backlogs from stalling on the CPU-only embedder - #2237
Stop large embedding backlogs from stalling on the CPU-only embedder#2237JSv4 wants to merge 6 commits into
Conversation
EMBEDDER_BATCH_REQUEST_TIMEOUT_SECONDS was 60s while a batch of 100 long texts -- whole ordinance sections and statute chapters, as produced by authority-pack ingestion -- routinely takes longer than that on CPU. On timeout the client retried the ENTIRE batch three times, so each task burned ~3 minutes and requeued having made no progress. Observed on a real ingest: a ~2,800-task queue draining at ~1 task/min with a continuous retry storm, and semantic search returning "no results from either arm" because no annotation ever received an embedding. The corpus agent silently fell back to general knowledge and answered a local-code question wrong. Raise the batch timeout to 300s and cut the microservice batch cap from 100 to 32, so a slow batch completes once instead of being redone three times. EMBEDDING_API_BATCH_SIZE drops 50 -> 32 to keep it <= the cap and satisfy the documents.E001 system check. Measured on the same queue, before and after, with one worker: retries continuous -> 0 completed 4 per 4 min -> 117 per 4 min Also adds the manual test procedure for the Fort Worth homeowner pack and corpus, which is where this surfaced. Note: opencontractserver/tests/test_batch_embedding.py and test_embedding_manager.py are intermittently failing (3 failures, vector dim 1536 != 3072) on this machine BOTH with and without this change -- verified by stashing it and re-running. Pre-existing flakiness, untouched here.
ReviewThis is a small, well-scoped config change with strong evidence behind it (real ingest measurements, before/after retry counts). A few notes: Code quality
Potential considerations (not blockers)
Test coverage
SecurityNo concerns — this is a constants-only change with no new input handling, auth, or permission surface. Overall: solid, well-justified fix with good measurement backing it up. Nothing blocking. |
Review: Stop large embedding backlogs from stalling on the CPU-only embedderSolid, well-diagnosed fix — the "retrying an already-slow batch 3x makes it worse, not better" root cause is convincing, and the before/after measurement (4 → 117 tasks/4min) is good evidence. A couple of things worth addressing before/after merge: 1. Stale docs/comments now describe a false invariant (
|
ReviewSmall, well-scoped fix backed by real production evidence (queue draining at ~1 task/min, silent fallback to general knowledge). Verified the change against the codebase: Correctness
Design / tradeoffs worth naming explicitly (not blockers)
Test coverage
Docs
Security / perf
Overall: a solid, well-evidenced fix with good reasoning documented in the code comments. No blocking issues found. |
…end on the install default
ReviewSolid, narrowly-scoped fix — the diagnosis (60s timeout < realistic CPU-embedder latency for long legal text → whole-batch retries → queue stall) is well-documented in the PR description and commit messages, and the before/after measurement (4 → 117 tasks/4min, continuous retries → 0) is convincing. The changelog fragment follows the Comments worth a look1. Stale rationale in
Both of these describe 2. Compounding retry latency at the new timeout — worth confirming, not necessarily a blocker 3. Test coverage — the empirical, real-ingest measurement in the PR description is good evidence, but there's no automated regression test pinning the new relationship between the three constants (beyond the existing Nits
Overall: low-risk, well-justified config change with real production evidence behind it. The two comment/docstring spots above are the only things I'd actually touch before merging; the retry-compounding point is more of a "worth knowing" than a required fix. |
ReviewSolid, well-diagnosed fix — the write-up connecting the 60s timeout → whole-batch retry → silent grounding failure is exactly the kind of root-cause analysis this repo's CLAUDE.md asks for, and the before/after throughput numbers (4 → 117 tasks/4min) are convincing. Correctness — looks right
One thing worth a second look — worst-case task blocking time
Not a blocker — the measured win is real and the previous 60s ceiling was clearly too aggressive — just flagging the tradeoff since the PR description doesn't discuss it. Minor / non-blocking
Test coveragePer the PR description, Overall: good fix, correctly scoped to the CPU-only embedder, backed by real measurements. The retry/timeout worst-case is the only thing I'd want confirmed before merging. |
What
EMBEDDER_BATCH_REQUEST_TIMEOUT_SECONDSwas 60s while a batch of 100 long texts — whole ordinance sections and statute chapters, as produced by authority-pack ingestion — routinely takes longer than that on a CPU-only embedder. On timeout the client retries the entire batch three times, so each task burns ~3 minutes and requeues having made no progress.How it surfaced
Ingesting a Fort Worth authority pack (881 sections) plus a 55-document corpus:
Hybrid search: no results from either armon every query, because no annotation ever received an embeddingThat last one is the reason this is filed as a bug rather than tuning: the failure is invisible at the API surface. Nothing errors. The agent just quietly stops being grounded.
Change
EMBEDDER_BATCH_REQUEST_TIMEOUT_SECONDSMICROSERVICE_EMBEDDER_MAX_BATCH_SIZEEMBEDDING_API_BATCH_SIZEA slow batch now completes once instead of being redone three times.
EMBEDDING_API_BATCH_SIZEdrops to keep it<=the cap and satisfy thedocuments.E001system check.Measured, same queue, one worker
Direct timing for calibration: 100 short texts embed in 25.6s, so the old 60s ceiling left almost no headroom for long legal text.
Tests
manage.py checkpasses. Embedder suites run (138 tests).opencontractserver/tests/test_batch_embedding.pyandtest_embedding_manager.pyare intermittently failing on this machine (3 failures, vector dim1536 != 3072) — verified pre-existing by stashing this change and re-running the same suites, which alternate FAILED/OK either way. Untouched here.Also adds
docs/test_scripts/fort_worth_homeowner_corpus.md, the manual procedure this surfaced under.