{"record":{"id":"971260966ebcbd63","repo":"ZhuLinsen/daily_stock_analysis","slug":"fastapi-timeout-seconds-1f-s-host","errorCode":null,"errorMessage":"FastAPI 服务在 {timeout_seconds:.1f}s 内未完成启动: {host}:{port}","messagePattern":"FastAPI 服务在 (.+?)s 内未完成启动: (.+?):(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"main.py","lineNumber":1274,"sourceCode":"            raise RuntimeError(\n                f\"FastAPI server failed to start: {host}:{port}; {startup_error[0]}\"\n            )\n        if uvicorn_server.started:\n            logger.info(f\"FastAPI 服务已启动: http://{host}:{port}\")\n            return\n        if not thread.is_alive():\n            break\n        time.sleep(0.05)\n\n    if startup_error:\n        raise RuntimeError(f\"FastAPI server failed to start: {host}:{port}; {startup_error[0]}\")\n    if uvicorn_server.started:\n        logger.info(f\"FastAPI 服务已启动: http://{host}:{port}\")\n        return\n    if not thread.is_alive():\n        raise RuntimeError(f\"FastAPI 服务器启动后立即退出: {host}:{port}\")\n\n    raise RuntimeError(f\"FastAPI 服务在 {timeout_seconds:.1f}s 内未完成启动: {host}:{port}\")\n\n\ndef _is_truthy_env(var_name: str, default: str = \"true\") -> bool:\n    \"\"\"Parse common truthy / falsy environment values.\"\"\"\n    value = os.getenv(var_name, default).strip().lower()\n    return value not in {\"0\", \"false\", \"no\", \"off\"}\n\n\ndef start_bot_stream_clients(config: Config) -> None:\n    \"\"\"Start bot stream clients when enabled in config.\"\"\"\n    # 启动钉钉 Stream 客户端\n    if config.dingtalk_stream_enabled:\n        try:\n            from bot.platforms import start_dingtalk_stream_background, DINGTALK_STREAM_AVAILABLE\n            if DINGTALK_STREAM_AVAILABLE:\n                if start_dingtalk_stream_background():\n                    logger.info(\"[Main] Dingtalk Stream client started in background.\")\n                else:","sourceCodeStart":1256,"sourceCodeEnd":1292,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/main.py#L1256-L1292","documentation":"The uvicorn thread is still alive after the 3-second deadline but uvicorn_server.started never became True — startup is proceeding but too slowly. The fixed 3.0s timeout is short for cold starts: first-time imports of the FastAPI app (pandas, LLM SDKs), lifespan hooks loading indices or connecting to external services can exceed it on slow disks or constrained CI runners.","triggerScenarios":"Heavy import chain (src/, data_provider, pandas) taking >3s on first run; lifespan startup doing network I/O (stock index refresh, DB connect) with no cache; machine under load (CI runner, low-CPU container); cold page cache after reboot.","commonSituations":"First --serve invocation in Docker where dependencies are imported lazily; CI smoke tests starting the server on shared runners; slow NFS/network filesystems holding the venv.","solutions":["Confirm the server eventually starts by running uvicorn server:app directly — if it comes up in e.g. 8s, raise timeout_seconds in main.py accordingly (or make it configurable).","Speed up app import: pre-warm imports in the main thread before spawning the server thread (imports are then cached).","Move slow lifespan work (index loads, network calls) to background tasks so started flips quickly.","On CI, use a longer timeout or a readiness poll against /health instead of this fixed window."],"exampleFix":"# before\n    timeout_seconds = 3.0\n\n# after\n    timeout_seconds = float(os.getenv(\"FASTAPI_STARTUP_TIMEOUT\", \"10\"))","handlingStrategy":"retry","validationCode":"import time, urllib.request\n\n# pre-warm imports in the main thread so the server thread starts fast\nimport server  # noqa: F401  (caches heavy modules)\ntime.sleep(0)  # optional: let page cache warm on cold hosts","typeGuard":null,"tryCatchPattern":"for timeout in (3.0, 15.0):\n    try:\n        run_fastapi_with_timeout(host, port, config, timeout)\n        break\n    except RuntimeError as e:\n        if \"未完成启动\" not in str(e):\n            raise\nelse:\n    raise  # still slow: profile app import / lifespan hooks","preventionTips":["Pre-import the app in the calling thread before spawning the server thread.","Keep lifespan hooks fast; move network/index loads to background tasks.","Make the startup timeout configurable via env for slow CI/containers."],"tags":["server","startup","timeout","performance"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}