fix(search): an indexer's HTTP timeout no longer aborts the whole search - #967
Draft
kevinheneveld wants to merge 1 commit into
Draft
kevinheneveld wants to merge 1 commit into
kevinheneveld wants to merge 1 commit into
Conversation
HttpClient.Timeout surfaces as a TaskCanceledException (inner TimeoutException), which every "when (ex is not OperationCanceledException)" clause in the indexer call chain deliberately lets through. So one slow indexer escaped the per-indexer catch, tore through Task.WhenAll and SearchService, and turned the request into an unhandled 500 — discarding the results the other indexers had already returned. Live case: a Torznab indexer that usually answers in ~1s occasionally took 28-60s; on the 60s expiry a Wanted-page "search-and-download" failed with "The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing" although three of four indexers had answered. HttpClientTimeoutClassifier tells the client-timeout shape apart from cooperative cancellation. IndexerSearchWorkflow.SearchIndexerAsync and the Torznab/Newznab provider now treat that shape as the indexer's own failure (warning + no results) so the fan-out keeps the other indexers' results; a genuine cancellation still propagates. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJkHHURUTS2m1QGHwn7xsC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
HttpClient.Timeoutsurfaces as aTaskCanceledException(innerTimeoutException). Everycatch (Exception ex) when (ex is not OperationCanceledException …)clause in the indexer call chain deliberately lets that type through, so one slow indexer escapes the per-indexer catch, tears throughTask.WhenAllandSearchService, and turns the request into an unhandled 500 — discarding the results the other indexers had already returned.Live case: a Torznab indexer that normally answers in ~1s occasionally took 28–60s. On the 60s expiry a Wanted-page
search-and-downloadfailed with "The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing" although three of four indexers had answered.Fix
HttpClientTimeoutClassifier(application/Common) tells the client-timeout shape (TaskCanceledException+ innerTimeoutException) apart from cooperative cancellation.IndexerSearchWorkflow.SearchIndexerAsyncandTorznabNewznabSearchProvider.SearchAsynctreat that shape as the indexer's own failure (warning + no results) so the fan-out keeps the other indexers' results. A genuine cancellation still propagates.Tests
IndexerSearchWorkflowTimeoutTests: a timing-out indexer next to a healthy one yields the healthy one's results; a realOperationCanceledExceptionstill propagates; the Torznab provider returns empty on anHttpClient.Timeout; classifier shape checks. PlusBackendArchitectureTestsand the existing Torznab parsing / SearchService tests.🤖 Generated with Claude Code
https://claude.ai/code/session_01WJkHHURUTS2m1QGHwn7xsC