Skip to content

feat(observability): worker 心跳告警闭环 + topic last_error 面板 - #52

Merged
Color2333 merged 1 commit into
mainfrom
feat/observability
Jul 18, 2026
Merged

feat(observability): worker 心跳告警闭环 + topic last_error 面板#52
Color2333 merged 1 commit into
mainfrom
feat/observability

Conversation

@Color2333

Copy link
Copy Markdown
Owner

背景

此前 worker 故障只记日志无人知:心跳过期只触发 docker restart(无人工告警),topic 抓取失败静默(last_error 被 API 用 CollectionAction.created_at 覆盖掩盖)。运维只能登服务器看日志发现问题。

修复

后端

  • apps/worker/main.py:心跳改写共享卷 /app/data/worker_heartbeat.json(pm_data 卷,backend 可读)+ 新增 heartbeat_alert_job(每 10min 自检):心跳过期 / 主题 last_error 非空 → 发告警邮件给 notify_default_to,带 1h 去重防刷屏(模块级 _last_alerts)。注册到 scheduler(*/10)。
  • scripts/worker_healthcheck.py:改读共享卷心跳(与 worker 写入对齐)。
  • apps/api/routers/topics.pylist_topics/_topic_dict 修复 last_run_at/last_error 掩盖——改读 TopicSubscription 真实抓取状态(PR1 存的),CollectionAction.created_at 改作 last_action_at 单独字段。加 ?failed=true 过滤。
  • apps/api/routers/system.py:新增 /system/worker 端点(读共享卷心跳返 {ts,error,age_seconds,is_stale});system_status 增补 worker_heartbeat + topic_errors 计数。

前端

  • types/index.tsTopiclast_error/last_action_at;新增 WorkerHeartbeat 类型;SystemStatusworker_heartbeat/topic_errors
  • services/api.tssystemApi.worker + topicApi.list(failed) + WorkerHeartbeat 导入。
  • pages/Operations.tsx:加 Worker 心跳面板(绿/红时效判定)+ 主题抓取错误面板(列表 last_error + 重新抓取按钮复用 topicApi.fetch)。mount 时加载。

验证

  • ruff / format / tsc --noEmit 全通过
  • pytest:61 passed, 2 skipped(新增 TestWorkerAlertDedup 去重+无收件人静默、TestTopicLastErrorExposed last_error 持久化+成功清空)
  • 告警去重逻辑:1h 窗口内同 key 不重复发;notify_default_to 未配置时静默跳过

部署影响

  • 心跳路径从 /tmp/worker_heartbeat 改到 /app/data/worker_heartbeat.json(共享卷),worker healthcheck 同步改,docker-compose 无需改(已用 python -m scripts.worker_healthcheck
  • 新增 worker 调度 job heartbeat_alert(每 10min)
  • 无新迁移、无新增配置项(复用 notify_default_to

不做(诚实标注)

  • Prometheus/监控仪表盘:文档提过但 docker-compose.monitoring.yml 不存在,aspiration,本轮不做
  • 告警渠道扩展(webhook/飞书):只做邮件,复用 NotificationService
  • 历史错误归档表:last_error 只存最近一次(单字段),不做错误历史表

此前 worker 故障只记日志:心跳过期只触发 docker restart(无人工告警),
topic 抓取失败静默(last_error 被 API 用 CollectionAction.created_at
覆盖掩盖)。运维只能登服务器看日志发现问题。

后端:
- apps/worker/main.py:心跳改写共享卷 /app/data/worker_heartbeat.json
  (pm_data 卷,backend 可读)+ 新增 heartbeat_alert_job(每10min自检):
  心跳过期/主题 last_error 非空 → 发告警邮件给 notify_default_to,
  带 1h 去重防刷屏(模块级 _last_alerts)。注册到 scheduler(*/10)。
- scripts/worker_healthcheck.py:改读共享卷心跳(与 worker 写入对齐)。
- apps/api/routers/topics.py:list_topics/_topic_dict 修复 last_run_at/
  last_error 掩盖——改读 TopicSubscription 真实抓取状态(PR1 存的),
  CollectionAction.created_at 改作 last_action_at 单独字段。加 ?failed=true
  过滤(只返回 last_error 非空的 topic,供面板)。
- apps/api/routers/system.py:新增 /system/worker 端点(读共享卷心跳返
  {ts,error,age_seconds,is_stale});system_status 增补 worker_heartbeat +
  topic_errors 计数。

前端:
- types/index.ts:Topic 加 last_error/last_action_at;新增 WorkerHeartbeat
  类型;SystemStatus 加 worker_heartbeat/topic_errors。
- services/api.ts:systemApi.worker + topicApi.list(failed) + WorkerHeartbeat 导入。
- pages/Operations.tsx:加 Worker 心跳面板(绿/红时效判定)+ 主题抓取错误
  面板(列表 last_error + 重新抓取按钮复用 topicApi.fetch)。mount 时加载。

测试:新增 TestWorkerAlertDedup(去重+无收件人静默)、TestTopicLastErrorExposed
(last_error 持久化+成功清空),全套 61 passed。tsc --noEmit 通过。
@github-actions

Copy link
Copy Markdown

🔍 OpenCode PR Review Required

这是一个受保护的分支,merge 前需要进行 code review。

请运行以下命令进行 OpenCode review:

/oc review https://github.com/Color2333/PaperMind/pull/$PR_NUM

或者在 PR 页面评论 /oc 来触发 OpenCode review。


This is an automated reminder from PR Review Gate.

@Color2333
Color2333 merged commit b57b1de into main Jul 18, 2026
2 checks passed
@Color2333
Color2333 deleted the feat/observability branch July 18, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant