{"record":{"id":"5f95f422c63a3a2f","repo":"ZhuLinsen/daily_stock_analysis","slug":"task-name-ranking-fetch-timeout","errorCode":null,"errorMessage":"{task_name} ranking fetch timeout","messagePattern":"(.+?) ranking fetch timeout","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"src/services/market_hotspot_service.py","lineNumber":428,"sourceCode":"                \"fundamental_fetch_timeout_seconds\",\n                DEFAULT_RANKING_FETCH_TIMEOUT_SECONDS,\n            )\n            return max(0.0, float(value))\n        except Exception:\n            return DEFAULT_RANKING_FETCH_TIMEOUT_SECONDS\n\n    @classmethod\n    def _call_with_timeout(\n        cls,\n        task: Callable[[], Any],\n        *,\n        timeout_seconds: float,\n        task_name: str,\n        inflight_key: Optional[Hashable] = None,\n    ) -> Any:\n        timeout_value = max(0.0, float(timeout_seconds))\n        if timeout_value <= 0:\n            raise TimeoutError(f\"{task_name} ranking fetch timeout\")\n\n        effective_inflight_key = inflight_key or task_name\n        future = cls._get_or_submit_ranking_fetch(\n            task,\n            inflight_key=effective_inflight_key,\n            task_name=task_name,\n        )\n        try:\n            return future.result(timeout=timeout_value)\n        except FutureTimeoutError as exc:\n            if future.done() and future.exception(timeout=0) is exc:\n                raise\n            cls._mark_ranking_fetch_timeout(\n                effective_inflight_key,\n                future,\n                retry_after=time.monotonic()\n                + max(timeout_value, RANKING_FETCH_TIMEOUT_RETRY_DELAY_SECONDS),\n            )","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/market_hotspot_service.py#L410-L446","documentation":"TimeoutError(f'{task_name} ranking fetch timeout') is raised by MarketHotspotService._call_with_timeout when the configured timeout_seconds is zero or negative (timeout_value = max(0.0, float(timeout_seconds)); if timeout_value <= 0 it raises immediately). It is a configuration/validation failure raised before any fetch is attempted — distinct from the 'after {n}s' variant which reflects a real elapsed timeout.","triggerScenarios":"Calling _call_with_timeout (directly or via a ranking fetch helper) with timeout_seconds=0, a negative number, or a value that float()s to 0 (e.g. '0', 0.0); typically a miscomputed timeout from configuration like timeout = base * factor where factor is 0.","commonSituations":"A config knob (e.g. ranking fetch timeout) set to 0 in .env intending 'no wait' but meaning 'fail fast', unit tests passing 0 to force timeout paths, or a timeout derived from a market-hours calculation that returns 0 outside trading windows.","solutions":["Check the caller of _call_with_timeout and print the timeout_seconds being passed for the failing task_name","Set a positive timeout (e.g. 3-10s) in the relevant configuration entry","If 0 was meant as 'use default', map 0/None to a sensible default before calling instead of passing it through","Guard unit tests that intentionally pass 0 with pytest.raises(TimeoutError)"],"exampleFix":"# before\ntimeout_seconds = int(os.getenv(\"RANKING_TIMEOUT\", \"0\"))\n\n# after: default to 5s when unset or zero\ntimeout_seconds = int(os.getenv(\"RANKING_TIMEOUT\", \"5\") or \"5\")\ntimeout_seconds = timeout_seconds if timeout_seconds > 0 else 5","handlingStrategy":"validation","validationCode":"timeout_seconds = float(timeout_seconds)\nif timeout_seconds <= 0:\n    timeout_seconds = DEFAULT_RANKING_TIMEOUT  # e.g. 5.0\n# now safe to call _call_with_timeout","typeGuard":"def is_positive_timeout(value: Any) -> bool:\n    try:\n        return float(value) > 0\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":null,"preventionTips":["Clamp configured timeouts to a sane positive default at load time","Treat 0/empty config values as 'unset', never as a valid timeout","Unit-test the timeout configuration path"],"tags":["timeout","configuration","market-data","validation"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}