{"record":{"id":"1a07a85ec218698c","repo":"ZhuLinsen/daily_stock_analysis","slug":"fastapi-host-port","errorCode":null,"errorMessage":"FastAPI 服务器启动后立即退出: {host}:{port}","messagePattern":"FastAPI 服务器启动后立即退出: (.+?):(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"main.py","lineNumber":1272,"sourceCode":"    while time.time() < wait_deadline:\n        if startup_error:\n            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():","sourceCodeStart":1254,"sourceCodeEnd":1290,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/main.py#L1254-L1290","documentation":"After the wait loop, the uvicorn server thread is dead, no exception was captured, and uvicorn_server.started is False — the process exited silently right after launch. Usually uvicorn received a shutdown signal, install-level signal handlers interfered, or run_server returned without raising (swallowed exception path).","triggerScenarios":"SIGTERM/SIGINT reaching the daemon thread during startup; use_config_signal_handlers interacting badly with the environment; run_server exiting normally because uvicorn_server.run() returned immediately (e.g. empty/None app passed after an import returned None); an exception type not derived from Exception (SystemExit, KeyboardInterrupt) bypassing the except clause and killing the thread silently.","commonSituations":"Running under a supervisor or test harness that delivers signals at startup; the app object import returning None; KeyboardInterrupt during the 3s startup window.","solutions":["Check whether anything sends signals to the process at startup (supervisor, docker stop, CI timeout) and delay or disable that.","Verify the imported ASGI app is a real object: python -c \"import server; print(server.app)\".","Broaden the except in run_server to BaseException (or add logging on thread exit via threading.excepthook) so silent deaths become diagnosable.","Retry once after clearing the environment (stray SIGINT from a terminal job-control issue)."],"exampleFix":"# before\n    def run_server():\n        try:\n            uvicorn_server.run()\n        except Exception as exc:  # SystemExit/KeyboardInterrupt vanish silently\n            startup_error.append(exc)\n\n# after\n    def run_server():\n        try:\n            uvicorn_server.run()\n        except BaseException as exc:  # capture silent thread deaths\n            startup_error.append(exc)","handlingStrategy":"try-catch","validationCode":"import threading\nthreading.excepthook = lambda args: logger.error(\"thread %s died: %s\", args.thread.name, args.exc_value)  # install before server start","typeGuard":null,"tryCatchPattern":"try:\n    run_fastapi(host, port, config)\nexcept RuntimeError as e:\n    if \"立即退出\" in str(e):\n        logger.error(\"server thread died silently; check signals and app import\")\n        subprocess.run([sys.executable, \"-c\", \"import server\"], check=True)  # preflight\n        raise","preventionTips":["Ensure supervisors/CI do not deliver SIGTERM during the startup window.","Verify the ASGI app object is non-None before handing it to uvicorn.","Capture BaseException in the server thread so silent exits become reported errors."],"tags":["server","startup","thread","silent-exit"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}