Files
reader/issues/mcp-timeout-job-running.md
T

2.1 KiB
Raw Blame History

[bug] MCP start_article_summary_job 超时但 job 实际执行了

问题描述

连续多个 start_article_summary_job 调用报 MCP 超时(-32001 Request timed out),但 job 实际执行了:

  • run_state.json 显示 status: failed,current_stage: generate_markdown
  • job 目录正常生成,run-state.json 存在于 outputs/freshrss/article_summary_jobs/<job-id>/
  • generate_markdown 阶段实际执行过(有结果),但 MCP 响应没能发回来

根因分析

server.py 的 start_article_summary_job handler 用同步方式处理请求:

proc = subprocess.Popen(
    cmd,
    cwd=str(REPO_ROOT),
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    start_new_session=True,
)
# ← Popen 返回后,server 主进程在发送 stdio 响应前被阻塞
return {
    "job_id": job_id,
    "status": "running",
    ...
}  # ← 这里应该立即返回,但可能被某种同步操作卡住

job 启动流程本身没问题(subprocess 确实被启动并执行了),问题出在 MCP server 发送响应的环节。

可能的阻塞点:

  1. store.save() 或 store.finish_stage() 涉及的磁盘锁
  2. stdio 响应的序列化或写入
  3. MCP server 的某种并发控制

修复方向

将 job 启动改造为真正的非阻塞模式:

  • 方案 A(推荐): 用后台线程/线程池(concurrent.futures.ThreadPoolExecutor)启动 job runner,主线程立即返回响应
  • 方案 B: 改用纯异步模式,job 状态完全通过 get_article_summary_job_status 查询

正确处理(临时 workaround)

当 MCP 调用 start_article_summary_job 超时后,不应立即判定 job 失败:

  1. 调用 get_article_summary_job_status(job_id) 查询真实状态
  2. 若返回 status=running 或 run_state.json 存在且 status=running → job 在跑,继续等待
  3. 若返回 status=failed → 查 run_state.json 的 failed_stage 和 error_summary

影响范围

  • OpenClaw MCP 客户端调用 start_article_summary_job
  • 任何通过 stdio MCP 通道使用 article summary job 的场景

复现时间

2026-04-16