LearnNewsExamplesServices
Frontmatter
id16973
titleA 30-minute timeout retries after 2 seconds, so retries queue behind their own orphans
stateClosed
labels
bugaiperformance
assigneesneo-gpt
createdAtAug 11, 2026, 3:49 PM
updatedAtAug 11, 2026, 5:27 PM
githubUrlhttps://github.com/neomjs/neo/issues/16973
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 11, 2026, 5:27 PM

A 30-minute timeout retries after 2 seconds, so retries queue behind their own orphans

Closed Backlog/active-chunk-15 bugaiperformance
neo-opus-grace
neo-opus-grace commented on Aug 11, 2026, 3:49 PM

Third defect in the batch chain, distinct from #16963 (retries re-buy identical embeddings) and from the batch-size ceiling. Measured on the affected external plane today.

The defect

VectorService.mjs:792 retries an embedding batch with a transient-error backoff:

lastError = err;
retries++;
console.error(`An error occurred during embedding batch ${n}. Retrying (${retries}/${maxRetries})...`);
if (retries < maxRetries) {
    await new Promise(res => setTimeout(res, 2 ** retries * 1000));   // 2s, 4s, 8s, 16s
}

The error being retried can be a 1,800,000ms timeout. So after abandoning a batch at 30 minutes, the next attempt is issued 2 seconds later.

Why that is worse than wasted work

A client-side timeout stops us waiting. It does not reliably stop the provider — measured in the model container's own log:

13:36:10 | 200 | 1h6m23s | POST /api/embed
         | Error #01: write tcp …->…:53210: write: broken pipe

That request ran to completion for 66 minutes and then failed to write its reply, because nobody was listening. An orphan, directly observed.

With OLLAMA_NUM_PARALLEL=1, retry n+1 is therefore dispatched onto a provider that may still be executing attempt n. Five retries at 2/4/8/16-second spacing against work that takes 30+ minutes means the retries stack behind their own abandoned attempts, and each one waits out the previous orphan before it even starts. The 1h6m23s row is consistent with exactly that: one attempt waiting out another.

Why it is a separate ticket

  • #16963 — retries re-buy identical embeddings. That is wasted work; this is wasted concurrency. Fixing the re-buy still leaves a retry racing an orphan.
  • batch-size ceiling (owned by @neo-opus-vega) — makes each attempt smaller. That reduces how often a timeout fires; it does not make the backoff correct when one does.
  • This one is cheap and independent of both.

The rule

A backoff must be at least as long as the work it just abandoned.

An exponential backoff answers "the provider glitched, try again shortly". A timeout answers something different: "we stopped waiting for work that may still be running." Retrying that in 2 seconds is not a retry, it is a second concurrent attempt.

Acceptance criteria

  • AC-1 — a retry after a TIMEOUT-class error waits at least the timeout budget that was just consumed, not 2^n seconds.
  • AC-2 — NON-VACUITY: non-timeout errors keep the existing fast exponential backoff. A refused chunk or a malformed payload must not wait 30 minutes; that would trade this defect for a slower one.
  • AC-3 — the classification is on the error, not on elapsed wall-clock, so a fast-failing provider is not mistaken for a timeout.
  • AC-4 — the retry log line states which backoff class it took and why, since the current line reports only the attempt number.
  • AC-5 — the total bounded retry cost is stated in the config's own words, because maxRetries × budget is now the real ceiling and nothing says so.

Deltas

  • This does not make a batch complete. It stops retries competing with themselves. The batch ceiling is what makes an attempt finish, and it is the one that unblocks ingestion.
  • Measured, not inferred: the 66-minute orphan and the 30m0s aborts are in the model container log; the 1800000ms timeout and the retry ladder are in the orchestrator log and in source.
tobiu referenced in commit 10a29b1 - "fix(knowledge-base): stop retrying provider timeouts in-cycle (#16973) (#16978)" on Aug 11, 2026, 5:27 PM
tobiu closed this issue on Aug 11, 2026, 5:27 PM