ZhuLinsen/daily_stock_analysis · warning · TimeoutError
{task_name} ranking fetch timeout after {timeout_value:g}s
Error message
{task_name} ranking fetch timeout after {timeout_value:g}s What it means
TimeoutError(f'{task_name} ranking fetch timeout after {timeout_value:g}s') is raised in MarketHotspotService._call_with_timeout when future.result(timeout=timeout_value) raises FutureTimeoutError — i.e. the ranking fetch worker thread did not complete within the allotted wall-clock seconds, and the future itself did not already contain that exception. The inflight key is then put into a cooldown (retry_after = now + max(timeout, RANKING_FETCH_TIMEOUT_RETRY_DELAY_SECONDS)) so repeated calls back off instead of hammering the slow source.
Source
Thrown at src/services/market_hotspot_service.py:447
effective_inflight_key = inflight_key or task_name
future = cls._get_or_submit_ranking_fetch(
task,
inflight_key=effective_inflight_key,
task_name=task_name,
)
try:
return future.result(timeout=timeout_value)
except FutureTimeoutError as exc:
if future.done() and future.exception(timeout=0) is exc:
raise
cls._mark_ranking_fetch_timeout(
effective_inflight_key,
future,
retry_after=time.monotonic()
+ max(timeout_value, RANKING_FETCH_TIMEOUT_RETRY_DELAY_SECONDS),
)
raise TimeoutError(
f"{task_name} ranking fetch timeout after {timeout_value:g}s"
) from exc
@classmethod
def _get_or_submit_ranking_fetch(
cls,
task: Callable[[], Any],
*,
inflight_key: Hashable,
task_name: str,
) -> Future:
submitted: Future
worker: threading.Thread
with cls._ranking_fetch_futures_lock:
retry_entry = cls._ranking_fetch_retry_after.get(inflight_key)
now = time.monotonic()
if retry_entry is not None:
retry_future, retry_after = retry_entryView on GitHub (pinned to 5159bd72e8)
Solutions
- Measure the actual source latency with curl -w '%{time_total}' against the ranking endpoint and set the timeout to ~2-3x that
- Retry after the cooldown window (RANKING_FETCH_TIMEOUT_RETRY_DELAY_SECONDS = 0.2s minimum) rather than immediately re-calling
- Check network egress/proxy health if all task_names time out simultaneously
- If only one task_name fails, that specific data provider is degraded — rely on the service's per-source fallback instead of raising the global timeout
- Look for leaked in-flight futures (detached futures never completing) if timeouts persist even after the source recovers
Example fix
# before result = svc._call_with_timeout(fetch, timeout_seconds=1.5, task_name="eastmoney") # after: sized to observed p99 latency result = svc._call_with_timeout(fetch, timeout_seconds=6.0, task_name="eastmoney")
Defensive patterns
Strategy: retry
Try / catch
try:
data = MarketHotspotService._call_with_timeout(fetch, timeout_seconds=6.0, task_name=name)
except TimeoutError as exc:
if "after" in str(exc):
logger.warning("%s slow; cooling down, will retry later", name)
data = cached_ranking(name) # fallback to last good data Prevention
- Size timeouts from measured p99 latency of each ranking provider
- Keep a last-known-good cache of ranking data for timeout fallback
- Respect the built-in cooldown instead of hammering retries
When it happens
Trigger: A ranking data source (e.g. EastMoney/THS ranking endpoints behind MarketHotspotService) responding slower than the configured timeout; network degradation; the source hanging without reading the socket; or the timeout set lower than the source's typical latency.
Common situations: Upstream ranking API slowdowns during peak trading hours, cross-border network latency, a stale in-flight future from an earlier request still holding the slot, or timeouts tuned too tight after a provider change.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- {task_name} ranking fetch cooling down after previous timeou
- {task_name} ranking fetch in-flight limit reached
- {call_name} 调用超过 {wait_seconds:g}s,已放弃等待
- [AlphaVantage] HTTP request failed for {symbol}: {e}
- [Finnhub] HTTP request failed for {symbol}: {e}
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/512108040b26a28c.
Report an issue: GitHub.