feat: add async job entrypoint for freshrss pipeline
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# FreshRSS 主日报异步 job 方案
|
||||
|
||||
## 背景
|
||||
|
||||
当前 `run_freshrss_openclaw_pipeline` 虽然已经作为正式 MCP workflow 入口存在,但执行模型仍是**同步 MCP 调用**。这会带来几个现实问题:
|
||||
|
||||
1. OpenClaw / MCP wrapper 存在超时风险,尤其是 5-10 篇的正式日报批次。
|
||||
2. wrapper timeout 与真实 run 是否已落地,容易出现语义分离。
|
||||
3. 当前已有 `run-state.json`、`get_run_status`、`get_run_report`、`get_delivery_payload`,但**启动层**仍然是同步调用,不利于正式生产链路稳定运行。
|
||||
4. 单篇总结已经验证了“最小 async job + 轮询状态 + 读取结果”模型可行,主日报 run 应收敛到同一套运行模式。
|
||||
|
||||
## 目标
|
||||
|
||||
将 FreshRSS 主日报 run 改造成与 article-summary 类似的**最小真异步 job**:
|
||||
|
||||
- 启动即返回 `job_id`
|
||||
- 真正执行由后台子进程完成
|
||||
- 状态可轮询
|
||||
- 成功后可读取结构化结果
|
||||
- 业务逻辑继续复用既有 `run_freshrss_pipeline(...)`
|
||||
- 不推翻现有 run-state / result query 能力
|
||||
|
||||
## 非目标
|
||||
|
||||
本阶段不做:
|
||||
|
||||
- 分布式任务队列
|
||||
- 多 worker 调度
|
||||
- 任意 stage 的后台恢复编排
|
||||
- 并发控制中心
|
||||
- 主流程与 article-summary job 的通用抽象框架一次性大重构
|
||||
|
||||
先做最小可用。
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. **启动层异步化,执行核心不重写**
|
||||
- `run_freshrss_pipeline(...)` 继续是主业务逻辑真相。
|
||||
- async job 只负责启动、状态持久化、结果回读。
|
||||
|
||||
2. **run truth 与 job truth 分层**
|
||||
- job truth:这次异步任务有没有启动、运行到哪一步、是否成功。
|
||||
- run truth:真正的 freshrss workflow 输出与 `run-state.json`。
|
||||
|
||||
3. **OpenClaw 正式生产默认改为 async start path**
|
||||
- 启动走 async job
|
||||
- 状态和结果优先先看 job
|
||||
- 真正业务产物仍由现有 run 查询工具承接
|
||||
|
||||
4. **与 article-summary job 尽量同构**
|
||||
- 目录结构
|
||||
- `run-state.json` / `input.json` / `result.json` / `job-report.json`
|
||||
- 后台 runner 脚本
|
||||
|
||||
## 拟新增能力
|
||||
|
||||
### MCP tools
|
||||
|
||||
新增 3 个工具:
|
||||
|
||||
- `start_freshrss_pipeline_job`
|
||||
- `get_freshrss_pipeline_job_status`
|
||||
- `get_freshrss_pipeline_job_result`
|
||||
|
||||
### job 目录
|
||||
|
||||
固定目录:
|
||||
|
||||
`outputs/freshrss/pipeline_jobs/<job_id>/`
|
||||
|
||||
至少包含:
|
||||
|
||||
- `run-state.json`
|
||||
- `input.json`
|
||||
- `result.json`(成功时)
|
||||
- `job-report.json`
|
||||
|
||||
### 执行模型
|
||||
|
||||
- `start_freshrss_pipeline_job` 写入 input + 初始化 job state
|
||||
- 后台 `subprocess.Popen(...)` 启动 runner
|
||||
- runner 内部调用 `run_freshrss_pipeline(...)`
|
||||
- 成功后把 `run_id`、核心产物路径、关键计数写入 `result.json`
|
||||
|
||||
## job 输入参数
|
||||
|
||||
与现有 `run_freshrss_openclaw_pipeline` 尽量对齐:
|
||||
|
||||
- `limit`
|
||||
- `mark_read`
|
||||
- `include_read`
|
||||
- `debug_artifacts`
|
||||
- `continuation`
|
||||
- `timeout_seconds`
|
||||
- `max_retries`
|
||||
- `stream_id`
|
||||
- `api_base_url`
|
||||
- `username`
|
||||
- `api_password`
|
||||
- `llm_api_key`
|
||||
- `llm_model`
|
||||
- `llm_api_url`
|
||||
- `context`
|
||||
- `run_id`
|
||||
- `date_value`
|
||||
- `output_dir`
|
||||
- `include_item_reports`
|
||||
|
||||
## 返回语义
|
||||
|
||||
### start
|
||||
|
||||
返回:
|
||||
|
||||
- `job_id`
|
||||
- `workflow`
|
||||
- `run_type`
|
||||
- `status=running`
|
||||
- `output_dir`
|
||||
- `message`
|
||||
|
||||
### status
|
||||
|
||||
返回:
|
||||
|
||||
- `job_id`
|
||||
- `status`
|
||||
- `current_stage`
|
||||
- `started_at` / `updated_at` / `finished_at`
|
||||
- `progress`
|
||||
- `artifacts`
|
||||
- `error_summary`
|
||||
- 若主 run 已创建,可附带 `linked_run_id`
|
||||
|
||||
### result
|
||||
|
||||
成功时返回:
|
||||
|
||||
- `job_id`
|
||||
- `status=success`
|
||||
- `run_id`
|
||||
- `delivery_output`
|
||||
- `report_output`
|
||||
- `digest_brief_output`
|
||||
- `pulled_count`
|
||||
- `delivered_count`
|
||||
- `marked_read_count`
|
||||
- `artifact`
|
||||
- `result`
|
||||
|
||||
## stages 建议
|
||||
|
||||
最小 job stages:
|
||||
|
||||
1. `prepare_job`
|
||||
2. `load_input`
|
||||
3. `run_pipeline`
|
||||
4. `write_result`
|
||||
|
||||
其中 `run_pipeline` 内部仍由现有 freshrss workflow 自己写它的 run-state。
|
||||
|
||||
## 与现有同步入口的关系
|
||||
|
||||
### 保留
|
||||
|
||||
`run_freshrss_openclaw_pipeline` 暂时保留,作为:
|
||||
|
||||
- debug / light path
|
||||
- 本地调试工具
|
||||
- 向后兼容路径
|
||||
|
||||
### 正式语义调整
|
||||
|
||||
文档与 OpenClaw handoff 中,主日报正式生产默认启动入口改为:
|
||||
|
||||
- `start_freshrss_pipeline_job`
|
||||
|
||||
同步入口降级为:
|
||||
|
||||
- debug / fallback
|
||||
- 小批量验证
|
||||
|
||||
## OpenClaw 编排建议
|
||||
|
||||
新的推荐路径:
|
||||
|
||||
1. `start_freshrss_pipeline_job`
|
||||
2. `get_freshrss_pipeline_job_status`
|
||||
3. 成功后 `get_freshrss_pipeline_job_result`
|
||||
4. 后续仍用:
|
||||
- `get_run_status`
|
||||
- `get_delivery_payload`
|
||||
- `get_run_report`
|
||||
- `list_run_artifacts`
|
||||
|
||||
## 风险点
|
||||
|
||||
1. **job 成功但 run 部分失败**
|
||||
- 允许,job 结果应以真实 `run_freshrss_pipeline(...)` 返回为准。
|
||||
- `run_id` + `report_output` 仍是最终真相。
|
||||
|
||||
2. **runner 崩溃但来不及写 result**
|
||||
- 需保证 `job-report.json` 至少能写下失败摘要。
|
||||
|
||||
3. **重复状态源导致混淆**
|
||||
- 文档必须明确:
|
||||
- job state 管“启动任务”
|
||||
- run state 管“业务工作流真相”
|
||||
|
||||
4. **同步 / 异步双入口长期漂移**
|
||||
- 必须要求 async job 内部直接复用 `run_freshrss_pipeline(...)`
|
||||
- 禁止再实现一套平行主流程
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 能通过 MCP 启动一个主日报 async job 并立即返回 `job_id`
|
||||
2. 能轮询到 `running -> success/failed`
|
||||
3. 成功后 `result.json` 含 `run_id` 与核心产物路径
|
||||
4. 对应 run 仍能通过既有 `get_run_status` / `get_run_report` / `get_delivery_payload` 正常读取
|
||||
5. README / handoff / TODO / plans 同步更新
|
||||
|
||||
## 建议实施顺序
|
||||
|
||||
1. 复制 article-summary job 骨架到 freshrss pipeline job
|
||||
2. 新增 runner 脚本
|
||||
3. server.py 暴露 3 个新工具
|
||||
4. 补 query/result 读法
|
||||
5. 更新 README / handoff
|
||||
6. 将 TODO 主任务切到“主日报 async job”
|
||||
Reference in New Issue
Block a user