步骤4阶段1 D2执行方案

源文件:D:\Hermes\reports\步骤4阶段1_D2执行方案.md · 日期 2026-09-14 · 6KB

步骤4阶段1 D2执行方案

制定日期: 2026-09-14
前置条件: D1观察通过(90次运行,100%成功)


任务1:D2时间窗口确认

当前时间

2026-09-14 08:31

选项对比

选项 受控测试 集成 回归验证 总计 优点 缺点
A 今天15:30-16:30 明天08:30-09:30 明天20:00-20:30 2.5h 分散压力 跨两天
B ⭐ 明天08:30-09:30 明天15:30-16:30 明天20:00-20:30 2.5h 集中执行 一天密集
C 今天15:30-17:30 今天20:00-21:00 - 3h 今天完成 时间紧凑

推荐方案:选项B

明天(9月15日)全天执行:
  08:30-09:30  受控测试(4项,1小时)
  15:30-16:30  run_with_alert集成(1小时)
  20:00-20:30  回归验证(30分钟)

总计: 2.5小时

理由:
1. 今天盘前已过,无法做盘前测试
2. 明天完整一天,时间充裕
3. 盘前测试可覆盖真实交易时段
4. 盘后集成可避免盘中干扰


任务2:run_with_alert集成方式

三种方式对比

方式 操作 风险 比对新旧结果 回滚难度
A 修改4个P0任务cron命令 高(改生产配置) 难(无法并行) 中(需改回cron)
B ⭐ 新增影子cron,原cron不动 低(双系统并行) 易(同时运行比对) 低(删除影子cron)
C wrapper只读不执行 无(但不监控) 无法比对 N/A

推荐方式:B — 新增影子cron

架构:

原cron(生产)          影子cron(测试)
┌─────────────┐       ┌─────────────┐
│ eval_morning│       │ eval_morning│
│ (正常执行)  │   →   │ (alert包装) │
└──────┬──────┘       └──────┬──────┘
       │                     │
       ↓                     ↓
  原输出文件            alert_state.db
                        (task_runs/alerts)

具体实现:

# 影子cron配置(不修改原cron)
影子任务 = {
    "name": "[TEST] 盘前评估(影子)",
    "schedule": "0 8 * * 1-5",  # 与原cron相同
    "script": "run_with_alert.py",
    "args": ["eval_morning", "D:/Hermes/scripts/hb_morning_eval.py"],
    "deliver": "local",  # 不推TG,只写DB
    "enabled": True
}

比对方法:

-- 比对原任务 vs 影子任务运行结果
SELECT 
    t1.task_id as 原任务,
    t1.status as 原状态,
    t2.task_id as 影子任务,
    t2.status as 影子状态,
    CASE WHEN t1.status = t2.status THEN '一致' ELSE '偏差' END as 比对结果
FROM task_runs t1
JOIN task_runs t2 ON t1.start_time = t2.start_time
WHERE t1.task_id = 'eval_morning'
  AND t2.task_id = 'test_eval_morning_shadow'
  AND t1.start_time > '2026-09-15';

回滚方案:

# 一键回滚:禁用影子cron
hermes cron pause <影子任务id>

# 或彻底删除
hermes cron remove <影子任务id>

# DB清理(可选)
DELETE FROM task_runs WHERE task_id LIKE 'test_%';
DELETE FROM alerts WHERE task_id LIKE 'test_%';

任务3:受控测试4项执行方案

测试1:告警路径测试

前置条件:
- 影子cron已注册
- alert_state.db可用

执行步骤:

# 1. 插入测试任务到jobs.json(临时)
test_task = {
    "id": "test_alert_path_001",
    "name": "[TEST] 告警路径测试",
    "script": "test_fail.py",  # exit code 1
    "schedule": "*/1 * * * *",  # 每分钟
    "enabled": True
}

# 2. 验证告警生成
# 等待1分钟后检查:
# - alerts表有记录
# - silence_state已更新
# - TG消息已发送(debug模式)

# 3. 清理
DELETE FROM task_runs WHERE task_id = 'test_alert_path_001';
DELETE FROM alerts WHERE task_id = 'test_alert_path_001';

预期结果:
- ✅ task_runs记录:status='failed', exit_code=1
- ✅ alerts记录:alert_type='task_fail'
- ✅ TG消息:🔴 P0任务告警


测试2:超时路径测试

前置条件:
- 影子cron已注册

执行步骤:

# 1. 修改last_run_at为3小时前(模拟超时)
import sqlite3
from datetime import datetime, timedelta

conn = sqlite3.connect('D:/Hermes/data/state/alert_state.db')
conn.execute("""
    INSERT INTO task_runs (task_id, run_id, scheduled_time, start_time, status, exit_code)
    VALUES ('test_timeout_001', 'run_001', ?, ?, 'ok', 0)
""", (
    (datetime.now() - timedelta(hours=3)).isoformat(),
    (datetime.now() - timedelta(hours=3)).isoformat()
))
conn.commit()
conn.close()

# 2. 运行alert_channel_health.py
# 3. 验证超时检测

预期结果:
- ✅ alert_channel_health检测到超时
- ✅ 无TG告警(静默期内)


测试3:Dead-Man测试

前置条件:
- alert_channel_health cron正常运行

执行步骤:

# 1. 停掉alert_channel_health心跳30分钟
# (实际不执行,模拟)

# 2. 验证dead_mans_switch检测到
# 检查dead_mans_switch_alert.txt

预期结果:
- ✅ dead_mans_switch在30分钟后触发
- ✅ 生成告警文件


测试4:通道健康测试

前置条件:
- alert_channel_health cron正常运行

执行步骤:

# 1. 临时修改TG token为错误值
# (实际不执行,验证机制)

# 2. 验证静默期机制
# 检查silence_state表

预期结果:
- ✅ 首次失败:记录audit_log
- ✅ 5分钟内重复失败:静默抑制
- ✅ 5分钟后:恢复告警


D2执行时间表

明天(9月15日)

时间 任务 产出
08:30-09:00 受控测试1-2(告警路径+超时路径) 测试报告
09:00-09:30 受控测试3-4(Dead-Man+通道健康) 测试报告
15:30-16:00 run_with_alert影子cron注册 影子任务ID
16:00-16:30 比对原任务vs影子任务输出 比对报告
20:00-20:30 回归验证(确认无异常) 回归报告

验收标准

D2通过条件:
  ✓ 4项受控测试全部通过
  ✓ 影子cron稳定运行2小时
  ✓ 原任务与影子任务输出一致
  ✓ 无TG告警噪音
  ✓ 回滚方案可用

请确认方案后,等待明天执行D2。