|
|
|
|
|
# Agent Cron 任务部署最佳实践
|
|
|
|
|
|
|
|
|
|
|
|
**版本:** 1.0
|
|
|
|
|
|
**创建日期:** 2026-02-25
|
|
|
|
|
|
**作者:** 陈医生 (Eason) 👨⚕️
|
|
|
|
|
|
**基于:** 张大师运程推送重复发送问题教训
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## ⚠️ 问题回顾
|
|
|
|
|
|
|
|
|
|
|
|
### 问题现象
|
|
|
|
|
|
- 张大师的 21:00 运程推送,**每天发送两次**
|
|
|
|
|
|
- 陈医生(主 Gateway)和张大师(独立 Gateway)都推送了相同内容
|
|
|
|
|
|
|
|
|
|
|
|
### 根本原因
|
|
|
|
|
|
```
|
|
|
|
|
|
主 Gateway (端口 18789)
|
|
|
|
|
|
├── Agents: main, life
|
|
|
|
|
|
├── Cron: 张大师运程推送 ← 配置在这里!
|
|
|
|
|
|
└── 问题:Cron 在主 Gateway,但 agentId="life"
|
|
|
|
|
|
|
|
|
|
|
|
张大师 Gateway (端口 18790)
|
|
|
|
|
|
├── 独立运行
|
|
|
|
|
|
└── 也有自己的 cron 配置
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**架构错误:**
|
|
|
|
|
|
- Cron 任务配置在**主 Gateway**
|
|
|
|
|
|
- 但 `agentId: "life"` 指向张大师
|
|
|
|
|
|
- 两个 Gateway 都在运行
|
|
|
|
|
|
- 导致**双重触发**
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📋 核心原则
|
|
|
|
|
|
|
|
|
|
|
|
### 原则 1: 任务归属明确
|
|
|
|
|
|
|
|
|
|
|
|
> **Cron 任务应该配置在执行该任务的 Agent 所属的 Gateway 中**
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
✅ 正确:
|
|
|
|
|
|
张大师的运程推送 → 配置在张大师的 Gateway
|
|
|
|
|
|
|
|
|
|
|
|
❌ 错误:
|
|
|
|
|
|
张大师的运程推送 → 配置在主 Gateway
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 原则 2: 默认不重复推送
|
|
|
|
|
|
|
|
|
|
|
|
> **除非特殊说明需要同步推送,否则只在指定 Agent 推送一次**
|
|
|
|
|
|
|
|
|
|
|
|
- 默认:单一推送
|
|
|
|
|
|
- 同步推送:需要明确说明
|
|
|
|
|
|
|
|
|
|
|
|
### 原则 3: Gateway 职责分离
|
|
|
|
|
|
|
|
|
|
|
|
| Gateway | 职责 | Cron 任务 |
|
|
|
|
|
|
|---------|------|----------|
|
|
|
|
|
|
| **主 Gateway** (陈医生) | 系统管理、main Agent | 仅 main 相关任务 |
|
|
|
|
|
|
| **独立 Gateway** (张大师) | 专用功能 | 该 Agent 的所有任务 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🔧 正确配置方法
|
|
|
|
|
|
|
|
|
|
|
|
### 场景 A: 为张大师创建定时任务
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 1: 确定目标 Gateway**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 张大师的独立 Gateway
|
|
|
|
|
|
Gateway: 张大师 (端口 18790)
|
|
|
|
|
|
配置目录:/root/.openclaw-life/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 2: 配置 Cron**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 编辑张大师 Gateway 的 cron 配置
|
|
|
|
|
|
cat > /root/.openclaw-life/cron/jobs.json << 'EOF'
|
|
|
|
|
|
{
|
|
|
|
|
|
"version": 1,
|
|
|
|
|
|
"jobs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "unique-id-here",
|
|
|
|
|
|
"agentId": "life",
|
|
|
|
|
|
"name": "张大师 - 每日运程推送",
|
|
|
|
|
|
"schedule": {
|
|
|
|
|
|
"kind": "cron",
|
|
|
|
|
|
"expr": "0 21 * * *",
|
|
|
|
|
|
"tz": "Asia/Shanghai"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
EOF
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 3: 重启目标 Gateway**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
systemctl --user restart openclaw-gateway-life.service
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 场景 B: 为 main Agent 创建定时任务
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 1: 确定目标 Gateway**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 主 Gateway
|
|
|
|
|
|
Gateway: 陈医生 (端口 18789)
|
|
|
|
|
|
配置目录:/root/.openclaw/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 2: 配置 Cron**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cat > /root/.openclaw/cron/jobs.json << 'EOF'
|
|
|
|
|
|
{
|
|
|
|
|
|
"version": 1,
|
|
|
|
|
|
"jobs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"agentId": "main",
|
|
|
|
|
|
"name": "main Agent 的任务",
|
|
|
|
|
|
"schedule": {
|
|
|
|
|
|
"kind": "cron",
|
|
|
|
|
|
"expr": "0 9 * * *",
|
|
|
|
|
|
"tz": "Asia/Shanghai"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
EOF
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**步骤 3: 重启主 Gateway**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
systemctl --user restart openclaw-gateway.service
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🚫 常见错误
|
|
|
|
|
|
|
|
|
|
|
|
### 错误 1: 跨 Gateway 配置 Cron
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
// ❌ 错误:在主 Gateway 配置张大师的任务
|
|
|
|
|
|
/root/.openclaw/cron/jobs.json
|
|
|
|
|
|
{
|
|
|
|
|
|
"agentId": "life" // 张大师的 agentId
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 问题:
|
|
|
|
|
|
// - 主 Gateway 运行 cron
|
|
|
|
|
|
// - 唤醒 life Agent
|
|
|
|
|
|
// - 但张大师的独立 Gateway 也在运行
|
|
|
|
|
|
// - 可能双重触发
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**正确做法:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
// ✅ 正确:在张大师 Gateway 配置
|
|
|
|
|
|
/root/.openclaw-life/cron/jobs.json
|
|
|
|
|
|
{
|
|
|
|
|
|
"agentId": "life"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 错误 2: 未确认 Gateway 数量
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ❌ 错误:不知道有几个 Gateway 在运行
|
|
|
|
|
|
systemctl --user list-units | grep openclaw
|
|
|
|
|
|
# 应该先检查!
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**正确做法:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# ✅ 正确:先检查 Gateway 状态
|
|
|
|
|
|
systemctl --user list-units | grep openclaw
|
|
|
|
|
|
|
|
|
|
|
|
# 确认:
|
|
|
|
|
|
# - openclaw-gateway.service (主 Gateway)
|
|
|
|
|
|
# - openclaw-gateway-life.service (张大师 Gateway)
|
|
|
|
|
|
# - 还有其他吗?
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 错误 3: 假设"修复一次就永远有效"
|
|
|
|
|
|
|
|
|
|
|
|
**问题:**
|
|
|
|
|
|
- 昨天修复了配置
|
|
|
|
|
|
- 今天又出现重复推送
|
|
|
|
|
|
- 原因:配置被覆盖或备份文件干扰
|
|
|
|
|
|
|
|
|
|
|
|
**正确做法:**
|
|
|
|
|
|
1. 修复后立即验证
|
|
|
|
|
|
2. 第二天再次检查
|
|
|
|
|
|
3. 监控至少一个完整周期(24 小时)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## ✅ 验证清单
|
|
|
|
|
|
|
|
|
|
|
|
部署 Cron 任务后,必须验证:
|
|
|
|
|
|
|
|
|
|
|
|
### 部署前检查
|
|
|
|
|
|
- [ ] 确认目标 Gateway 是哪个
|
|
|
|
|
|
- [ ] 确认该 Gateway 的配置目录
|
|
|
|
|
|
- [ ] 确认是否有多个 Gateway 运行相同 Agent
|
|
|
|
|
|
|
|
|
|
|
|
### 部署后验证
|
|
|
|
|
|
- [ ] Cron 配置文件语法正确
|
|
|
|
|
|
- [ ] 重启了正确的 Gateway
|
|
|
|
|
|
- [ ] 检查 Gateway 日志,确认 cron 已加载
|
|
|
|
|
|
- [ ] 等待第一次执行,确认只推送一次
|
|
|
|
|
|
|
|
|
|
|
|
### 持续监控
|
|
|
|
|
|
- [ ] 第二天检查是否重复推送
|
|
|
|
|
|
- [ ] 检查 cron 执行日志
|
|
|
|
|
|
- [ ] 确认 delivery 状态
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📊 验证命令
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 检查 Gateway 状态
|
|
|
|
|
|
systemctl --user list-units | grep openclaw
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 检查 Cron 配置
|
|
|
|
|
|
cat /root/.openclaw/cron/jobs.json | python3 -m json.tool
|
|
|
|
|
|
cat /root/.openclaw-life/cron/jobs.json | python3 -m json.tool
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 检查 Cron 任务数量
|
|
|
|
|
|
cat /root/.openclaw*/cron/jobs.json | python3 -c "
|
|
|
|
|
|
import sys,json
|
|
|
|
|
|
for f in sys.stdin:
|
|
|
|
|
|
d=json.loads(f)
|
|
|
|
|
|
print(f'Tasks: {len(d.get(\"jobs\",[]))}')
|
|
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
# 4. 查看 Cron 执行日志
|
|
|
|
|
|
journalctl --user -u openclaw-gateway*.service | grep cron
|
|
|
|
|
|
|
|
|
|
|
|
# 5. 验证 Telegram 消息
|
|
|
|
|
|
# 手动检查 Telegram,确认没有重复推送
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🎯 决策树
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
需要创建定时任务
|
|
|
|
|
|
↓
|
|
|
|
|
|
哪个 Agent 执行?
|
|
|
|
|
|
├─→ main Agent → 配置在主 Gateway
|
|
|
|
|
|
└─→ 独立 Agent (如 life)
|
|
|
|
|
|
↓
|
|
|
|
|
|
该 Agent 有独立 Gateway 吗?
|
|
|
|
|
|
├─→ 是 → 配置在独立 Gateway
|
|
|
|
|
|
└─→ 否 → 配置在主 Gateway
|
|
|
|
|
|
↓
|
|
|
|
|
|
需要同步推送吗?
|
|
|
|
|
|
├─→ 是 → 在多个 Gateway 都配置 (明确说明)
|
|
|
|
|
|
└─→ 否 → 只在一个 Gateway 配置 (默认)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 📝 经验教训
|
|
|
|
|
|
|
|
|
|
|
|
### 教训 1: 架构决定配置位置
|
|
|
|
|
|
|
|
|
|
|
|
- **集中式架构** (所有 Agent 在主 Gateway) → Cron 都在主 Gateway
|
|
|
|
|
|
- **分布式架构** (Agent 有独立 Gateway) → Cron 分散到各 Gateway
|
|
|
|
|
|
|
|
|
|
|
|
**当前架构:** 混合架构
|
|
|
|
|
|
- 主 Gateway: main + life (路由)
|
|
|
|
|
|
- 独立 Gateway: life (张大师)
|
|
|
|
|
|
|
|
|
|
|
|
**正确做法:** 独立 Agent 的 Cron 配置在独立 Gateway
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 教训 2: 验证必须跨越完整周期
|
|
|
|
|
|
|
|
|
|
|
|
- **不要**修复后立即认为"已解决"
|
|
|
|
|
|
- **要**监控至少 24 小时(一个完整日周期)
|
|
|
|
|
|
- **要**在实际执行时间点验证
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 教训 3: 文档化架构决策
|
|
|
|
|
|
|
|
|
|
|
|
**应该记录:**
|
|
|
|
|
|
- 哪些 Agent 有独立 Gateway
|
|
|
|
|
|
- 每个 Gateway 的职责
|
|
|
|
|
|
- Cron 任务的归属
|
|
|
|
|
|
|
|
|
|
|
|
**不应该:**
|
|
|
|
|
|
- 假设"大家都知道"
|
|
|
|
|
|
- 依赖口头沟通
|
|
|
|
|
|
- 不写文档
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 🔗 相关文档
|
|
|
|
|
|
|
|
|
|
|
|
- [AGENT_DEPLOYMENT_BEST_PRACTICES.md](./AGENT_DEPLOYMENT_BEST_PRACTICES.md)
|
|
|
|
|
|
- [张大师部署日志](../logs/agents/life/2026-02-23-deployment-check.log)
|
|
|
|
|
|
- [张大师问题修复报告](../logs/agents/life/2026-02-23-issue-fixes.md)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
**最后更新:** 2026-02-25
|
|
|
|
|
|
**维护者:** 陈医生 (Eason) 👨⚕️
|