diff --git a/CHANGELOG.md b/CHANGELOG.md index d9d174b..b72de84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # 变更记录 +## 2026-08-25(凌晨)— 修复 watchdog.sh 误杀:把"采样跑完/VAE存盘中"当成卡死重启,打断了一批正在跑的任务 + +**背景**:批量重跑 16 个 h3-showcase 案例期间,队列跑到一半突然又出现"进程重启导致任务被取消/ +执行状态丢失"——5 个任务(1 个 failed + 4 个 cancelled)一次性被打断,一开始怀疑又是人为操作 +(跟8月24日PM2那次很像),查了才发现这次是机器自己的`watchdog.sh`干的。 + +**根因**:`watchdog.sh`(2026-08-23新增,按`step`字段判断任务卡死,不看总耗时)只区分了 +"FSDP初始化中(step=0)"和"denoise采样中(step>0)"两个阶段,没考虑到`step`到达`total_steps` +(采样跑完)之后还有VAE视频/音频解码+存盘这段没有独立进度信号的尾巴——`step`会一直停在最终值 +不变。这段被并入了denoise阶段的10分钟宽限,实测至少一个1344×768长帧数案例这个阶段本身就超过 +608秒,被误判"卡死"、自动`bash start.sh`整机重启,把当时排队中的一批任务连带打断。 + +**修复**:`watchdog.sh`给"`step>=total_steps`"这个采样完/存盘中阶段单独加一档30分钟宽限 +(`STALL_LIMIT_POSTPROC=1800`),不再跟denoise阶段共用10分钟的紧阈值。已部署并重启watchdog +进程(新PID替换旧的),被打断的5个任务已用存量`req_json`重新提交。详见 +`raylight/README.md`已知限制第10条。 + +**教训记录**:这台机器上至少有两套独立的自动重启机制(这个watchdog + 8月24日排查过的PM2托管 +服务),以后见到"进程重启导致任务被取消"这类错误,先查`watchdog.log`有没有"卡死判定触发", +比先怀疑人为操作更快定位。 + ## 2026-08-24(晚,续3)— 修复 raylight `/health` 骗人报健康的盲区,ComfyUI 崩了近20分钟没人发现 **背景**:续2记录的那次 ref2va OOM(`b659b60c6cbc`,FSDP初始化阶段GPU2/GPU3 OOM)实际上 diff --git a/docs/todo/h3-showcase-cases.md b/docs/todo/h3-showcase-cases.md index 490d12d..a301e99 100644 --- a/docs/todo/h3-showcase-cases.md +++ b/docs/todo/h3-showcase-cases.md @@ -53,11 +53,11 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 望远镜寻 MINIMAX 装置 | ref2va | 图1-4连续关键帧,已上传 | 已提交 | a59cae01ec39 | | +| 1 | 望远镜寻 MINIMAX 装置 | ref2va | 图1-4连续关键帧,已上传 | 已完成 | a59cae01ec39 | | | 2 | 史诗级太空歌剧院线短预告 | 纯文生(未确认) | 无/待确认 | 已完成 | 6639b07acc7b | | -| 3 | 科幻悬疑电影短预告 | ref2va | 图1氛围/图2人物,已上传 | 已提交 | 97846542ab09 | | -| 4 | 高级时尚品牌视频(荒漠公路) | ref2va | 图1场景/图2人物/图3包袋/图4logo,已上传 | 已提交 | c1237b599bf4 | | -| 5 | 火场胶片时尚短片 | ref2va | 图1质感/图2人物,已上传 | 已提交 | 67ababbea78f | | +| 3 | 科幻悬疑电影短预告 | ref2va | 图1氛围/图2人物,已上传 | 已完成 | 97846542ab09 | | +| 4 | 高级时尚品牌视频(荒漠公路) | ref2va | 图1场景/图2人物/图3包袋/图4logo,已上传 | 已完成 | c1237b599bf4 | | +| 5 | 火场胶片时尚短片 | ref2va | 图1质感/图2人物,已上传 | 已完成 | 67ababbea78f | |
提示词原文 @@ -85,7 +85,7 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 悬疑犯罪电影片头 | ref2va | 多张风格参考图(7张),已上传 | 已提交 | 81711242178d | | +| 1 | 悬疑犯罪电影片头 | ref2va | 多张风格参考图(7张),已上传 | 已完成 | 81711242178d | | | 2 | 傍晚厨房手绘发光动画 | 纯文生 | 无 | 已完成 | c0e23beb4132 | | | 3 | 深夜自助洗衣店手绘发光动画 | 纯文生 | 无 | 已完成 | 0fe0f2101c44 | | | 4 | 手绘2.0,海边小集市指物变手绘 | 纯文生 | 无 | 已完成 | eaf2a1433c41 | | @@ -113,7 +113,7 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | MiniMax H3 品牌开场 MG,波形 Logo | ref2va | 图1开场/图2波形logo,已上传 | 已提交 | 7ded7db676d3 | | +| 1 | MiniMax H3 品牌开场 MG,波形 Logo | ref2va | 图1开场/图2波形logo,已上传 | 已完成 | 7ded7db676d3 | | | 2 | MiniMax H3 品牌 MG「One becomes everyone」 | 纯文生 | 无 | 已完成 | 194e9bd77da6 | | | 3 | 全中文文字动效实验影像 | 纯文生 | 无 | 已完成 | 125751cac1c8 | | | 4 | Touch Designer 动效追踪 | ref2va(视频编辑) | @视频1基础素材 | 不支持 | | raylight 后端 GenReq 无"以视频为基础编辑"字段,无法提交 | @@ -167,7 +167,7 @@ |---|---|---|---|---|---|---| | 1 | 古装武侠悬疑短剧,竹林 | 纯文生(未确认) | 无/待确认 | 已完成 | 57169e6751d0 | | | 2 | 室内家庭争吵短剧(竖屏) | 纯文生 | 无 | 已完成 | 99e771bbb50d | 含具体人物「秦皓瑄」台词/语气要求 | -| 3 | 海外吸血鬼爱情短剧预告(竖屏) | ref2va | 图1男女主/图2场景,已上传 | 已提交 | 71a4d093aebc | 720×1280竖屏提交 | +| 3 | 海外吸血鬼爱情短剧预告(竖屏) | ref2va | 图1男女主/图2场景,已上传 | 已完成 | 71a4d093aebc | 720×1280竖屏提交 |
提示词原文 @@ -189,8 +189,8 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 高级时尚眼镜广告,白棚双模特 | ref2va | 图1模特/图2外貌/图3眼镜,已上传 | 已提交 | b0d258352c3c | 720×1280竖屏提交 | -| 2 | Herman Miller 人体工学椅 360 展示 | ref2va | 图1产品详情/图2产品图,已上传(仅1张) | 已提交 | fe749aa533a0 | 文档里图1图2视觉上是同一素材,只上传了1张 | +| 1 | 高级时尚眼镜广告,白棚双模特 | ref2va | 图1模特/图2外貌/图3眼镜,已上传 | 已完成 | b0d258352c3c | 720×1280竖屏提交 | +| 2 | Herman Miller 人体工学椅 360 展示 | ref2va | 图1产品详情/图2产品图,已上传(仅1张) | 已完成 | fe749aa533a0 | 文档里图1图2视觉上是同一素材,只上传了1张 | | 3 | 北京烤鸭美食产品宣传 | 纯文生 | 无 | 已完成 | 4067993ff824 | |
提示词原文 @@ -213,9 +213,9 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 赛博朋克角色装备切换+UI+场景加载 | ref2va | 图1角色/图2 UI风格,已上传 | 已提交 | 2e18bf09b46a | 精确到秒的分镜时间轴,15s | -| 2 | 产品官网落地页 UI/UX 滚动演示 | ref2va | 图1产品图,已上传 | 已提交 | 234a2037e064 | | -| 3 | 网站 UI 标题滑动+汽车灯变色 | 按纯文生提交 | 无(提示词未引用@图片编号) | 已提交 | 88e3501a3fb9 | | +| 1 | 赛博朋克角色装备切换+UI+场景加载 | ref2va | 图1角色/图2 UI风格,已上传 | 已完成 | 2e18bf09b46a | 精确到秒的分镜时间轴,15s | +| 2 | 产品官网落地页 UI/UX 滚动演示 | ref2va | 图1产品图,已上传 | 已完成 | 234a2037e064 | | +| 3 | 网站 UI 标题滑动+汽车灯变色 | 按纯文生提交 | 无(提示词未引用@图片编号) | 已提交 | db125dc6a831 | | | 4 | 2D 手绘比格犬反应游戏界面 | 纯文生 | 无 | 已完成 | e1fd99e4ab97 | 原案例10s/4:3画幅,本次统一用1344×768/12.5s提交,用于观察分辨率适配效果 |
提示词原文 @@ -240,7 +240,7 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 机械臂抓取红色方块 | 纯文生 | 无 | 已提交 | 0a5ca897d076 | | +| 1 | 机械臂抓取红色方块 | 纯文生 | 无 | 已提交 | 282281777d1b | | | 2 | 精准替换视频背景为办公室场景 | 视频编辑 | 基于案例1输出 | 不支持 | | raylight 后端无视频编辑输入方式,且依赖案例1先跑完 |
提示词原文 @@ -260,9 +260,9 @@ | # | 标题 | 模式 | 参考素材 | 状态 | 任务ID | 备注 | |---|---|---|---|---|---|---| -| 1 | 黏土动画狐狸跃崖 | 纯文生 | 无 | 已提交 | 760588dc9f82 | | -| 2 | 国风仙侠 3D 角色 PV | ref2va | 图1分镜/图2人物,已上传 | 已提交 | 28244b583d2d | | -| 3 | 乙游男主角色 PV | ref2va | 图2角色身份,已上传(合并图) | 已提交 | 329ed81249cd | 截图时未拆分图1/图2,用了含所需人物信息的合并图 | +| 1 | 黏土动画狐狸跃崖 | 纯文生 | 无 | 已提交 | 1a398591663e | | +| 2 | 国风仙侠 3D 角色 PV | ref2va | 图1分镜/图2人物,已上传 | 已提交 | 423a20afba5a | | +| 3 | 乙游男主角色 PV | ref2va | 图2角色身份,已上传(合并图) | 已提交 | d040eec16a88 | 截图时未拆分图1/图2,用了含所需人物信息的合并图 |
提示词原文 diff --git a/raylight/README.md b/raylight/README.md index dbbbca6..1138414 100644 --- a/raylight/README.md +++ b/raylight/README.md @@ -139,6 +139,19 @@ ssh admin@192.168.110.67 'cd /data/models/minimax-h3 && export H3_OFFLOAD=disk & 探测一次8188,探测失败就把`ready`降级成0、`model`字段报`"comfyui_unreachable"`,不再 单纯相信内存里那个只写一次的标志位。**这条不能顶替第8条**——探测准了只是能更快发现 崩溃,8188死了以后还是要手动`bash start.sh`重启,自愈本身仍然没有。 +10. **【2026-08-25修复】`watchdog.sh`的卡死判定漏了"采样跑完、VAE解码存盘中"这个阶段, + 把正常任务当卡死误杀重启**——`watchdog.sh`(2026-08-23新增,按`step`字段判断任务是否 + 卡死,见该脚本文件头注释)只区分"FSDP初始化中(step=0,20分钟宽限)"和"denoise采样中 + (step>0,10分钟宽限)"两个阶段,没考虑到`step`到达`total_steps`后(采样已经跑完)还有 + VAE视频/音频解码+存盘这段没有独立进度信号的尾巴,`step`会一直停在最终值不变。这段被 + 并入了10分钟宽限那档,实测至少一个1344×768长帧数案例这个阶段本身就超过608秒—— + watchdog判定"卡死"、自动执行`bash start.sh`整机重启,把当时排队中的一整批任务 + (h3-showcase-cases批量测试,5个)连带打断,跟"服务被别人手动重启"表现完全一样, + 一开始容易误判成人为操作。**已修**:给`step>=total_steps`这个"采样完/存盘中"阶段单独 + 一档`STALL_LIMIT_POSTPROC=1800`(30分钟宽限),不再跟denoise阶段共用10分钟的紧阈值。 + **排查经验**:见到"进程重启导致任务被取消"这类错误,先查`watchdog.log`有没有 + "卡死判定触发"字样,比先怀疑人为操作或`start.sh`被谁手动跑了更快定位——这台机器上 + 至少有两套独立的自动重启机制(这个watchdog + 8月24日排查过的PM2),别再默认是人。 ## 多参考图生视频支持参考视频/独立音频参考(2026-08-24 新增) diff --git a/raylight/watchdog.sh b/raylight/watchdog.sh new file mode 100644 index 0000000..9669b0a --- /dev/null +++ b/raylight/watchdog.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# 基于进度的卡死检测,取代之前"固定600秒墙钟时间"的误杀判定(2026-08-23)。 +# 判定标准:denoise 的 step 数字长时间不变才算卡死,不看总耗时——大分辨率/长帧数任务本来 +# 就该跑更久,不该被时间线误杀。 +# +# 【2026-08-25修复】漏了一个阶段:采样跑完(step达到total_steps)之后还有VAE视频/音频解码+ +# 存盘,这段没有独立进度信号,step会一直停在最终值不变——之前这段直接被并入 +# STALL_LIMIT_RUNNING(10分钟)判定,实测至少一个1344×768长帧数案例这个阶段本身就超过608秒, +# 被误判"卡死"重启,把一批正常在跑/排队的任务(showcase案例批次)集体打断。单独给这个阶段 +# 一个更宽的阈值,跟INIT阶段同样的思路——不同阶段没有可比的"正常耗时",不能共用一个数字。 +set -uo pipefail +BASE="http://127.0.0.1:8100" +STATE_FILE="/data/models/raylight/watchdog.state" +LOG_FILE="/data/models/raylight/watchdog.log" +STALL_LIMIT_RUNNING=600 # denoise 采样中(0=total_steps),VAE解码/存盘阶段,给30分钟宽限 +POLL_INTERVAL=20 + +log() { echo "$(date '+%F %T') $*" >> "$LOG_FILE"; } + +# 状态文件格式:job_id step last_change_epoch +read_state() { cat "$STATE_FILE" 2>/dev/null || echo "none 0 0"; } +write_state() { echo "$1 $2 $3" > "$STATE_FILE"; } + +log "watchdog started" + +while true; do + sleep "$POLL_INTERVAL" + + HEALTH=$(curl -s --max-time 10 "$BASE/health" 2>/dev/null) + RUNNING=$(echo "$HEALTH" | python3 -c "import sys,json; print(json.load(sys.stdin).get('running',0))" 2>/dev/null) + if [ "$RUNNING" != "1" ]; then + write_state none 0 0 + continue + fi + + JOBS=$(curl -s --max-time 10 "$BASE/v1/videos?limit=5" 2>/dev/null) + CUR=$(echo "$JOBS" | python3 -c " +import sys, json +try: + jobs = json.load(sys.stdin) + for j in jobs: + if j.get('status') == 'running': + print(j['id']); break +except Exception: + pass +" 2>/dev/null) + [ -z "$CUR" ] && continue + + DETAIL=$(curl -s --max-time 10 "$BASE/v1/videos/$CUR" 2>/dev/null) + STEP=$(echo "$DETAIL" | python3 -c "import sys,json; print(json.load(sys.stdin).get('step',0))" 2>/dev/null) + [ -z "$STEP" ] && STEP=0 + TOTAL_STEPS=$(echo "$DETAIL" | python3 -c "import sys,json; print(json.load(sys.stdin).get('total_steps',0))" 2>/dev/null) + [ -z "$TOTAL_STEPS" ] && TOTAL_STEPS=0 + + read -r PREV_ID PREV_STEP PREV_TS < <(read_state) + NOW=$(date +%s) + + if [ "$CUR" != "$PREV_ID" ] || [ "$STEP" != "$PREV_STEP" ]; then + write_state "$CUR" "$STEP" "$NOW" + log "job=$CUR step=$STEP (progress, reset stall timer)" + continue + fi + + STALLED_FOR=$((NOW - PREV_TS)) + if [ "$STEP" = "0" ]; then + LIMIT=$STALL_LIMIT_INIT + elif [ "$TOTAL_STEPS" != "0" ] && [ "$STEP" -ge "$TOTAL_STEPS" ] 2>/dev/null; then + LIMIT=$STALL_LIMIT_POSTPROC + else + LIMIT=$STALL_LIMIT_RUNNING + fi + + if [ "$STALLED_FOR" -ge "$LIMIT" ]; then + log "job=$CUR step=$STEP 卡死判定触发:$STALLED_FOR 秒无进展(阈值 $LIMIT),执行重启" + bash /data/models/raylight/start.sh >> "$LOG_FILE" 2>&1 + write_state none 0 0 + log "重启完成" + fi +done