{"record":{"id":"0b2088877e0deaf1","repo":"ZhuLinsen/daily_stock_analysis","slug":"pytdx-temporarily-unavailable-self-last-unavail","errorCode":null,"errorMessage":"Pytdx temporarily unavailable: {self._last_unavailable_reason or 'connection cooldown'}","messagePattern":"Pytdx temporarily unavailable: (.+?)","errorType":"exception","errorClass":"DataSourceUnavailableError","httpStatus":null,"severity":"warning","filePath":"data_provider/pytdx_fetcher.py","lineNumber":199,"sourceCode":"            logger.warning(\"pytdx 未安装，请运行: pip install pytdx\")\n            return None\n    \n    @contextmanager\n    def _pytdx_session(self) -> Generator:\n        \"\"\"\n        Pytdx 连接上下文管理器\n        \n        确保：\n        1. 进入上下文时自动连接\n        2. 退出上下文时自动断开\n        3. 异常时也能正确断开\n        \n        使用示例：\n            with self._pytdx_session() as api:\n                # 在这里执行数据查询\n        \"\"\"\n        if self._is_in_connection_cooldown():\n            raise DataSourceUnavailableError(\n                f\"Pytdx temporarily unavailable: {self._last_unavailable_reason or 'connection cooldown'}\"\n            )\n\n        TdxHq_API = self._get_pytdx()\n        if TdxHq_API is None:\n            raise DataFetchError(\"pytdx 库未安装\")\n        \n        api = TdxHq_API()\n        connected = False\n        \n        try:\n            # 尝试连接服务器（自动选择最优）\n            for i in range(len(self._hosts)):\n                host_idx = (self._current_host_idx + i) % len(self._hosts)\n                host, port = self._hosts[host_idx]\n                \n                try:\n                    if api.connect(host, port, time_out=5):","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/pytdx_fetcher.py#L181-L217","documentation":"DataSourceUnavailableError raised at the top of PytdxFetcher._pytdx_session() when the fetcher is in a connection cooldown (set by _mark_connection_cooldown after repeated TDX server connection failures). It signals 'back off, this provider is temporarily down' rather than a permanent failure, and includes the last recorded unavailability reason.","triggerScenarios":"Entering the _pytdx_session() context manager after a prior session failed to connect to any TDX host and marked cooldown; the cooldown timer has not yet expired, so every market-data call (get_security_bars, get_security_quotes, ...) raises immediately.","commonSituations":"TDX quote servers unreachable from the host (firewall, GFW-adjacent network, datacenter blocking port 7709); burst of requests after a network blip triggering cooldown; running scheduled analysis while the network is down.","solutions":["Treat this as transient: catch DataSourceUnavailableError in the DataFetcherManager chain and fall back to another A-share provider (Akshare/Tushare) for the cooldown window.","Fix the root cause of the cooldown: verify outbound TCP connectivity to the TDX hosts (default port 7709) and check _last_unavailable_reason in logs.","If cooldowns are too aggressive/long for your workload, tune the cooldown duration used by _mark_connection_cooldown."],"exampleFix":"# before\nwith fetcher._pytdx_session() as api:  # DataSourceUnavailableError during cooldown\n    data = api.get_security_bars(...)\n\n# after\ntry:\n    with fetcher._pytdx_session() as api:\n        data = api.get_security_bars(...)\nexcept DataSourceUnavailableError:\n    data = akshare_fetcher.get_stock_data(code, start, end)  # fallback provider","handlingStrategy":"fallback","validationCode":"if fetcher._is_in_connection_cooldown():\n    reason = fetcher._last_unavailable_reason or \"cooldown\"\n    logger.info(f\"pytdx in cooldown ({reason}); using fallback\")\n    df = akshare_fetcher.get_stock_data(code, start, end)","typeGuard":null,"tryCatchPattern":"try:\n    with fetcher._pytdx_session() as api:\n        data = api.get_security_bars(category=9, market=m, code=c, start=0, count=n)\nexcept DataSourceUnavailableError:\n    data = None  # manager moves to the next A-share provider; do not retry pytdx now","preventionTips":["Honor the cooldown: do not retry pytdx immediately after a cooldown marker.","Monitor _last_unavailable_reason in logs to catch chronic network problems early.","Always pair pytdx with a fallback provider in the chain."],"tags":["pytdx","cooldown","circuit-breaker","network","transient"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}