{"record":{"id":"242de7951bce67ba","repo":"ZhuLinsen/daily_stock_analysis","slug":"error-242de7","errorCode":null,"errorMessage":"题材新闻搜索进程未返回结果","messagePattern":"题材新闻搜索进程未返回结果","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/search_service.py","lineNumber":145,"sourceCode":"                daemon=True,\n            )\n            process.start()\n            process_started = True\n            child_conn.close()\n            child_conn = None\n\n            poll_seconds = (\n                wait_seconds\n                if deadline is None\n                else max(0.0, deadline - time.monotonic())\n            )\n            if poll_seconds <= 0 or not parent_conn.poll(poll_seconds):\n                _terminate_search_process(process)\n                raise TimeoutError(f\"题材新闻搜索超过 {wait_seconds:g}s，已终止请求进程\")\n            try:\n                ok, value = parent_conn.recv()\n            except EOFError as exc:\n                raise RuntimeError(\"题材新闻搜索进程未返回结果\") from exc\n        finally:\n            try:\n                if child_conn is not None:\n                    child_conn.close()\n            finally:\n                try:\n                    if parent_conn is not None:\n                        parent_conn.close()\n                finally:\n                    if process_started:\n                        try:\n                            process.join(_SEARCH_TIMEOUT_PROCESS_JOIN_GRACE_SECONDS)\n                        finally:\n                            _terminate_search_process(process)\n    finally:\n        # Capacity belongs to the accepted call, not to a successfully started\n        # process. Release it even if Process.start() or cleanup itself fails.\n        _SEARCH_TIMEOUT_WORKER_SLOTS.release()","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/search_service.py#L127-L163","documentation":"RuntimeError raised when parent_conn.recv() hits EOFError: the worker process closed its end of the pipe without sending the (ok, value) result tuple — i.e. it died (crash, kill, OOM, interpreter abort) instead of returning or raising through the protocol. Distinct from a timeout: the pipe signaled EOF, not silence.","triggerScenarios":"The subprocess worker raising an unhandled exception that kills the process before send, being OOM-killed by the kernel, terminated externally (container limits, supervisor), or aborting during native-code scraping dependencies (segfault in a parser).","commonSituations":"Memory limits in containers killing the worker; an unhandled error path in a provider only triggered by specific topics; native dependency crashes (lxml/ICU mismatches); SIGTERM from orchestration during a run.","solutions":["Check process-level logs (dmesg for OOM-kill, container restart events) for why the worker died","Retry once — a one-off crash may not reproduce; persistent EOF on the same topic indicates a deterministic bug","Reproduce by running the provider chain in-process for the failing topic to surface the real traceback","Raise memory limits or reduce per-search result volume if the worker is being OOM-killed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = search_topic_news(topic)\nexcept RuntimeError as exc:\n    if \"未返回结果\" in str(exc):\n        log.error(\"Search worker died for topic %r — check OOM/crash logs\", topic)\n        run_provider_chain_in_process_for_debug(topic)  # surface real traceback\n    raise","preventionTips":["Monitor for OOM-kills in containers running search workers","Keep an in-process debug mode to reproduce worker crashes with full tracebacks","Add a fallback path (skip topic news) so a dying worker degrades, not fails, the report"],"tags":["subprocess","search","crash","eof"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}