我用 TraeWork 搭建数据平台自动巡检,告别每天人工盯盘

我是谁 & 遇到什么问题

我是大数据开发工程师,负责数据仓库的日常运维和任务调度。

在新接手的项目中有一些需要经常监控的服务情况,包括dolphin调度情况、hive作业状态、flink任务状态,但是遇到了一个很头疼的问题:

项目原来的监控服务过期了不可用,并且原来的监控服务也无法完全按照要求监控全部这些情况,所以在接手项目初期,每天从早7点到晚11点隔一段时间就要人工巡检一下这些服务的状态,每天睡不好觉不说,有时候起晚了或者忘了检查,就会导致整个数据链路延迟,影响早上的报表产出。

我用了 TraeWork 解决了这件事

模式: :check_box_with_check: Work :check_box_with_check: Code ☐ Design

我主要用了 TraeWork 的这几个能力:

  • 自动化任务(定时执行):设置定时调度,每2小时进行一次巡检并报告
  • 代码执行与脚本编写:让 TraeWork 的CODE模式帮我写服务检查和发送监控报告的 Python 脚本
  • 飞书插件: 检查结果直接同步到飞书群,可以随时用手机查看结果,还可以拉更多同事进群一起协作

具体做法:

  • 用 TraeWork 的CODE模式帮我写了一个 Python 脚本,通过API模拟登录并获取当前各个服务的状态,并根据个性化的逻辑和要求来进行筛选和判断,生成的监控报告以飞书卡片的形式发送到飞书群
  • 设置定时任务,每2小时自动进行一次巡检

我做出了什么

一套完整的自动巡检 + 报告推送方案:

  • 4 个 Python 脚本(三个服务检查脚本+一个结果分析并推送飞书脚本)
  • 每2小时自动执行的定时巡检任务,也可在手机端主动触发检查
  • 手机实时同步检查结果,异常作业一目了然

效果展示

  1. 飞书收到的巡检结果通知:

  1. 积分消耗情况:

  1. 自动化任务配置:

经验 & 技巧总结

  1. 积分消耗优化:能写到脚本里的逻辑全部写到脚本里,尽量不用AI做任何多余的分析,能用一个任务完成的事情就不要用两个任务。通过任务合并、脚本实现的方式,将原本第一版本的每次巡检累计需要150多积分的任务优化成了每次仅需要1.5积分左右。

  2. 先在本地调试通脚本再上定时任务:一开始我直接让 TraeWork 写好脚本就设了定时任务,结果因为 API 的认证问题跑失败了。建议先手动跑几次脚本,确认能正常拿到数据、逻辑正确,再配置定时调度。

  3. 异常阈值不要设得太激进:我一开始把超时阈值设成了 1 小时,结果有些大表的 join 任务本来就需要跑很久,被误判成卡死了,导致形成的检查报告有很多无效信息。后来根据实际作业的历史运行时长调整到 10 小时,就没有再误报过。建议根据自己集群的实际情况调整阈值。

提示词参考

  1. 查询脚本编写提示词(Code模式, 以flink任务状态查询为例)
参考项目中的监控脚本和提示词,我打算写一个新的监控脚本和提示词,用于监控dinky中的flink执行情况。下面是相关的可能需要的接口: 
 一:登录接口:
 
 https://bd-dinky.in.ykt.eduyun.cn/api/login 
 
 参数示例:
 
 {"username":"xxxxxx","password":"xxxxxx","autoLogin":true,"tenantId":3,"type":"password"}
 
 
 二:查询接口:
 
 https://bd-dinky.in.ykt.eduyun.cn/api/jobInstance/getStatusCount 
 
 结果示例:
 {
     "datas": {
         "instance": {
             "all": 12,
             "initializing": 0,
             "running": 11,
             "finished": 0,
             "failed": 0,
             "canceled": 1,
             "restarting": 0,
             "created": 0,
             "failing": 0,
             "cancelling": 0,
             "suspended": 0,
             "reconciling": 0,
             "unknown": 0
         },
         "history": {
             "all": 1822,
             "initializing": 1,
             "running": 11,
             "finished": 0,
             "failed": 1399,
             "canceled": 395,
             "restarting": 0,
             "created": 0,
             "failing": 0,
             "cancelling": 0,
             "suspended": 0,
             "reconciling": 0,
             "unknown": 16
         }
     },
     "code": 0,
     "msg": "获取成功",
     "time": "2026-08-06 07:15:59"
 } 
 
 当instance和history里的running的数量都为11时,才是正常状态,否则都是不正常的。 
 
 现在,先帮我写一下python脚本,查询getStatusCount的结果
  1. 结果分析脚本提示词:
# 数据平台统一监控任务

## 功能

合并 Dolphin、Hue、Dinky 三个监控脚本为一个统一任务脚本,依次运行三个脚本,分别解析输出并判断状态,最终将所有监控结果汇总为**一张飞书交互式卡片(interactive card)**发送到 "edu 监控告警群"(chat_id: oc_7aa9da4b561b1903a7xxxxxxxxxx)。

## 执行步骤

1. **依次运行三个脚本**
   - 执行命令:`python3 dolphinscheduler_jobs.py`
   - 执行命令:`python3 hue_jobs.py`
   - 执行命令:`python3 dinky_jobs.py`
   - 分别捕获各脚本的标准输出和错误输出

2. **分别解析输出**

   ### 2.1 Dolphin 解析
   - 识别任务信息字段(project_name、process_define_name、state、running_type、schedule_time、start_time)
   - **过滤条件:仅保留 state 为失败的、且 project_name 不为"中小学quality数据监控"的记录**

   ### 2.2 Hue 解析
   - 识别任务信息字段(job_id、name、status、duration、start_time 等)
   - **过滤条件:过滤掉 Apache Flink 类型的任务**
   - 重点标记:运行时间超过 10 小时(>=10小时 或 >=600分钟)的任务

   ### 2.3 Dinky 解析
   - 识别 `=== Status Check ===` 段落
   - 提取关键字段:
     - `Expected running count`:预期正常运行数(应为 11)
     - `Actual instance running`:当前实例(instance)实际 running 数
     - `Actual history running`:历史实例(history)实际 running 数
     - `Result`:NORMAL 或 ABNORMAL
   - 同时解析上方的 `Instance (当前实例)` 和 `History (历史实例)` 状态明细(各状态计数:all / running / finished / failed / canceled 等)
   - 正常条件:`instance.running == 11` 且 `history.running == 11`(严格等于,多了少了都算异常)

3. **汇总判断**
   - 三个监控项各自独立判断正常/异常
   - 汇总状态:全部正常 → 整体正常卡片;任一异常 → 整体异常卡片
   - 统计异常项数量,用于 subtitle 展示

4. **构造飞书卡片并发送**
   - 根据汇总结果构造**一张** Card 2.0 交互式卡片 JSON
   - 卡片内按 Dolphin → Hue → Dinky 顺序分三个区块展示
   - 通过 `lark-cli im +messages-send --chat-id oc_7aa9da4b561b1903a7xxxxxxxx --msg-type interactive --content '<卡片JSON>'` 发送

## 卡片格式规范

### 卡片通用要求
- 使用 Card 2.0(`"schema": "2.0"`)
- 禁止使用 `:warning:` `:red_circle:` 等 GitHub shortcode,飞书不解析;用 Card 2.0 header icon(如 `warning_colorful`)替代
- 禁止使用 `--markdown` 发送,必须用 `--msg-type interactive --content` 发送卡片
- 卡片内三个监控区块之间用 `hr` 分割线分隔

### 1. 当三个监控项全部正常时
- **header**:`green` 模板 + `checklist_colorful` 图标 + `text_tag_list`(绿色"正常"标签)
- **title**:`数据平台监控:全部正常`
- **subtitle**:`Dolphin / Hue / Dinky 三项监控均正常`
- **宽度模式**:`default`
- **body 结构**(三个区块,用 hr 分隔):

  **区块一 - Dolphin:**
  - markdown 组件:`**🐬 Dolphin 调度任务**`
  - markdown 组件:`今日无失败任务 ✅`

  **hr 分割线**

  **区块二 - Hue:**
  - markdown 组件:`**🐝 Hue 作业**`
  - markdown 组件:`所有非 Flink 任务运行时间均在正常范围内 ✅`

  **hr 分割线**

  **区块三 - Dinky:**
  - markdown 组件:`**⚡ Dinky Flink 实例**`
  - markdown 组件:`instance.running = 11,history.running = 11,运行状态正常 ✅`

### 2. 当任一监控项异常时
- **header**:`red` 模板 + `warning_colorful` 图标 + `text_tag_list`(红色"异常"标签)
- **title**:`数据平台监控:发现异常`
- **subtitle**:`共 N 个监控项异常,请关注`(N 为异常项数量)
- **宽度模式**:`fill`
- **body 结构**(三个区块,用 hr 分隔,每个区块独立展示正常或异常详情):

  每个区块的规则:
  - 区块标题:`**🐬 Dolphin 调度任务**` / `**🐝 Hue 作业**` / `**⚡ Dinky Flink 实例**`
  - 若该监控项**正常**:标题后追加一个 markdown 组件,展示简要正常信息(同上"全部正常"时的文案)
  - 若该监控项**异常**:标题后追加 markdown 提示语 + `table` 组件展示详情

  #### Dolphin 异常时表格列定义

  | 列名 (name) | 表头 (display_name) | data_type | 说明 |
  |---|---|---|---|
  | project_name | 项目名称 | text | 项目名称 |
  | process_define_name | 工作流名称 | text | 工作流名称 |
  | state | 状态 | options | `[{"text":"失败","color":"red"}]` 红色标签 |
  | running_type | 运行类型 | text | 如"调度执行" |
  | schedule_time | 调度时间 | text | 如"2026-08-05 03:30:00" |
  | start_time | 开始时间 | text | 如"2026-08-05 03:30:00" |

  - Dolphin 异常时提示语:`**以下任务运行失败,请关注:**`

  #### Hue 异常时表格列定义

  | 列名 (name) | 表头 (display_name) | data_type | 说明 |
  |---|---|---|---|
  | job_id | 任务ID | text | 任务ID |
  | name | 任务名称 | text | 任务名称 |
  | duration | 运行时间 | text | 如"12小时30分" |
  | status | 状态 | options | `[{"text":"RUNNING","color":"yellow"}]` 等颜色标签 |
  | suggestion | 建议 | text | 如"检查是否需要终止或优化" |

  - Hue 异常时提示语:`**以下任务运行时间超过10小时,建议关注:**`

  #### Dinky 异常时表格列定义

  | 列名 (name) | 表头 (display_name) | data_type | 说明 |
  |---|---|---|---|
  | category | 分类 | text | `当前实例(Instance)` 或 `历史实例(History)` |
  | all | 总数 | text | all 数量 |
  | running | Running | options | 若等于 11 显示 `[{"text":"11","color":"green"}]`;否则 `[{"text":"X","color":"red"}]` |
  | finished | Finished | text | finished 数量 |
  | failed | Failed | text | failed 数量 |
  | canceled | Canceled | text | canceled 数量 |
  | other | 其他状态 | text | 汇总其余非零状态(initializing/restarting/unknown 等),如 `unknown:16`,无则 `-` |
  | status | 判断结果 | options | 正常 `[{"text":"正常","color":"green"}]`,异常 `[{"text":"异常","color":"red"}]` |

  - Dinky 异常时提示语:`**以下 Flink 实例运行状态异常,请关注:**`
  - Dinky 异常时若 instance 和 history 状态不同,status 列分别标注

  #### 表格通用设置
  - 所有 `table` 的 `header_style` 设为 `{"background_style":"grey","bold":true,"lines":1}`
  - 所有 `table` 的 `page_size` 设为 10

### 卡片 JSON 示例(Dolphin 正常、Hue 异常、Dinky 异常时)
{
  "schema": "2.0",
  "config": { "update_multi": true, "width_mode": "fill" },
  "header": {
    "title": { "tag": "plain_text", "content": "数据平台监控:发现异常" },
    "subtitle": { "tag": "plain_text", "content": "共 2 个监控项异常,请关注" },
    "template": "red",
    "icon": { "tag": "standard_icon", "token": "warning_colorful" },
    "text_tag_list": [
      { "tag": "text_tag", "text": { "tag": "plain_text", "content": "异常" }, "color": "red" }
    ]
  },
  "body": {
    "direction": "vertical",
    "padding": "12px 12px 20px 12px",
    "elements": [
      { "tag": "markdown", "content": "**🐬 Dolphin 调度任务**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "今日无失败任务 ✅", "margin": "0px 0px 8px 0px" },
      { "tag": "hr" },
      { "tag": "markdown", "content": "**🐝 Hue 作业**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "**以下任务运行时间超过10小时,建议关注:**", "margin": "0px 0px 8px 0px" },
      {
        "tag": "table",
        "columns": [
          { "name": "job_id", "display_name": "任务ID", "data_type": "text" },
          { "name": "name", "display_name": "任务名称", "data_type": "text" },
          { "name": "duration", "display_name": "运行时间", "data_type": "text" },
          { "name": "status", "display_name": "状态", "data_type": "options" },
          { "name": "suggestion", "display_name": "建议", "data_type": "text" }
        ],
        "rows": [
          { "job_id": "job_001", "name": "data_import", "duration": "12小时30分", "status": [{"text":"RUNNING","color":"yellow"}], "suggestion": "检查是否需要终止或优化" }
        ],
        "page_size": 10,
        "header_style": { "background_style": "grey", "bold": true, "lines": 1 },
        "margin": "0px 0px 8px 0px"
      },
      { "tag": "hr" },
      { "tag": "markdown", "content": "**⚡ Dinky Flink 实例**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "**以下 Flink 实例运行状态异常,请关注:**", "margin": "0px 0px 8px 0px" },
      {
        "tag": "table",
        "columns": [
          { "name": "category", "display_name": "分类", "data_type": "text" },
          { "name": "all", "display_name": "总数", "data_type": "text" },
          { "name": "running", "display_name": "Running", "data_type": "options" },
          { "name": "finished", "display_name": "Finished", "data_type": "text" },
          { "name": "failed", "display_name": "Failed", "data_type": "text" },
          { "name": "canceled", "display_name": "Canceled", "data_type": "text" },
          { "name": "other", "display_name": "其他状态", "data_type": "text" },
          { "name": "status", "display_name": "判断结果", "data_type": "options" }
        ],
        "rows": [
          { "category": "当前实例(Instance)", "all": "12", "running": [{"text":"10","color":"red"}], "finished": "0", "failed": "0", "canceled": "1", "other": "-", "status": [{"text":"异常","color":"red"}] },
          { "category": "历史实例(History)", "all": "1822", "running": [{"text":"10","color":"red"}], "finished": "0", "failed": "1399", "canceled": "395", "other": "unknown:16,initializing:1", "status": [{"text":"异常","color":"red"}] }
        ],
        "page_size": 10,
        "header_style": { "background_style": "grey", "bold": true, "lines": 1 }
      }
    ]
  }
}

### 卡片 JSON 示例(全部正常时)
{
  "schema": "2.0",
  "config": { "update_multi": true, "width_mode": "default" },
  "header": {
    "title": { "tag": "plain_text", "content": "数据平台监控:全部正常" },
    "subtitle": { "tag": "plain_text", "content": "Dolphin / Hue / Dinky 三项监控均正常" },
    "template": "green",
    "icon": { "tag": "standard_icon", "token": "checklist_colorful" },
    "text_tag_list": [
      { "tag": "text_tag", "text": { "tag": "plain_text", "content": "正常" }, "color": "green" }
    ]
  },
  "body": {
    "direction": "vertical",
    "padding": "12px 12px 20px 12px",
    "elements": [
      { "tag": "markdown", "content": "**🐬 Dolphin 调度任务**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "今日无失败任务 ✅", "margin": "0px 0px 8px 0px" },
      { "tag": "hr" },
      { "tag": "markdown", "content": "**🐝 Hue 作业**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "所有非 Flink 任务运行时间均在正常范围内 ✅", "margin": "0px 0px 8px 0px" },
      { "tag": "hr" },
      { "tag": "markdown", "content": "**⚡ Dinky Flink 实例**", "margin": "0px 0px 4px 0px" },
      { "tag": "markdown", "content": "instance.running = 11,history.running = 11,运行状态正常 ✅" }
    ]
  }
}

## 注意事项

- 如果脚本输出格式与预期不同,根据实际输出调整解析逻辑
- 三个脚本的执行相互独立,某个脚本失败不影响其他两个的解析和展示
- 如果某个脚本执行失败(如登录失败、接口报错),该监控区块展示红色错误信息,其他区块正常展示
- Dolphin 过滤条件:state 为失败 **且** project_name 不为"中小学quality数据监控"
- Hue 过滤条件:过滤掉 Apache Flink 类型的任务,仅标记运行时间超过 10 小时的非Flink任务
- Hue 运行时间计算需考虑不同时间格式(小时:分钟、Xh Ym、纯分钟数等)
- Dinky Running 数的判断是严格等于 11,**不是 >=11**:多了少了都算异常
- Dinky `other` 列汇总:除 all/running/finished/failed/canceled 以外,所有非零状态,格式如 `unknown:16,initializing:1`,顺序按脚本中输出顺序;全部为 0 则填 `-`
- 脚本执行失败时,对应监控区块展示:`❌ 脚本执行失败:<错误详情>`
- 本次操作禁止产生任何本地文件,直接将结果发送到飞书群
- 最终只发送**一张**合并卡片,严禁分多条消息发送
- 严格按照卡片格式规范构造 JSON 并发送,严禁输出任何多余内容
  1. 定时任务提示词(极简)
直接运行`python ./edu_monitor.py`

不知道哪个版本开始,自动化任务记录不再同步到移动端了,稍微改造了一下,接入了飞书插件,将监控结果以飞书卡片消息的方式推送到了飞书群,比之前利用三端同步来同步到Trae移动端来看的方式更好了,并且可以在群里拉人让更多人关注监控结果