Skip to content

fix(search): one indexer timeout no longer discards every other indexer's results#757

Open
t3chnaztea wants to merge 1 commit into
Listenarrs:canaryfrom
t3chnaztea:fix/indexer-timeout-aborts-search
Open

fix(search): one indexer timeout no longer discards every other indexer's results#757
t3chnaztea wants to merge 1 commit into
Listenarrs:canaryfrom
t3chnaztea:fix/indexer-timeout-aborts-search

Conversation

@t3chnaztea

Copy link
Copy Markdown

The bug

The per-indexer catch in IndexerSearchWorkflow.SearchIndexersAsync excluded OperationCanceledException from its filter. An HttpClient per-request timeout throws TaskCanceledException — a subclass of OperationCanceledException — so a single slow or timing-out indexer escaped the per-indexer handling, propagated out of Task.WhenAll, and discarded every healthy indexer's results for the whole search. On the automatic path that zeroes out the entire cycle for that book until the next sweep.

The fix

Catch OperationCanceledException per-indexer, log a warning naming the indexer, and return an empty list for that indexer only — matching how other per-indexer failures already behave. No workflow-level CancellationToken flows into this search (verified across the call chain, incl. IIndexerSearchProvider.SearchAsync), so an OCE here can only be a client timeout; there is no shutdown cancellation to preserve. OutOfMemoryException/StackOverflowException remain excluded.

Tests

  • SearchIndexersAsync_OneIndexerTimesOut_ReturnsHealthyIndexerResults
  • SearchIndexersAsync_AllIndexersTimeOut_ReturnsEmptyWithoutThrowing

Full suite green: 1191 passed / 0 failed; dotnet format --verify-no-changes clean.

🤖 Generated with Claude Code

…er's results

An HttpClient timeout surfaces as TaskCanceledException, a subclass of
OperationCanceledException. The per-indexer catch in the parallel search loop
excluded OperationCanceledException, so a single slow/timing-out indexer's
exception escaped the catch, propagated out of Task.WhenAll, and discarded every
healthy indexer's results for the whole search (zeroing the automatic cycle for
the book). No workflow-level cancellation token flows into SearchIndexersAsync,
so any OCE there is a per-request timeout: catch it per-indexer, log a warning
naming the indexer, and return an empty result for that indexer only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3chnaztea
t3chnaztea requested a review from a team July 13, 2026 02:51
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