三个状态字段回答的是不同问题:
video_diagnosis
video_status
upload_status
UpsertProducts 已经在每次全量拉取时用货憨憨的 video_diagnosis 覆盖本地 (internal/store/product.go:118),前端「类型 = 缺少视频」筛的就是它。 所以「视频被删 → 重新拉取 → 能筛出来」这条链路目前是通的。
UpsertProducts
internal/store/product.go:118
筛得出来,但跑起来什么也不会发生。
某商品此前已上传成功(upload_status = 'done'),后来视频在上游被删除。 重新全量拉取后 video_diagnosis 变回 missing,界面能筛出这个商品, 但批量任务按 upload_status = 'done' 判定为已完成,直接跳过它。
upload_status = 'done'
missing
全量拉取发现某商品的视频在上游消失后,本地的工作流状态要随之修正, 使它能被重新处理;且已经下载到本地的视频直接重传,不重新搜淘宝。
ok
download_status
video_diagnosis = 'missing'
video_status = 'none'
pending
在 UpsertProducts 写入过程中,对每条商品比较写入前的旧 video_diagnosis 与本次拉取的新值。只处理 ok → missing 这一个方向。
ok → missing
新增商品(本地原本不存在)不适用本规则,它们本来就是 pending。
ok → missing 时:
本地已有下载完成的视频(videos 表存在该商品 status = 'downloaded' 的记录, 且 local_path 指向的文件仍然存在):
videos
status = 'downloaded'
local_path
本地没有可用视频:
video_status = 'none' 的含义是「我们拿这张主图去淘宝搜过,确实没有同款视频」。 这个结论是关于商品主图的,不是关于货憨憨状态的—— 货憨憨那边的视频被删,不会让淘宝突然多出一个同款视频。
若因 diagnosis = missing 就把 none 重置为 pending,会导致: 货憨憨永远说缺视频 → 我们永远搜不到 → 每批任务都重新搜一遍,无限循环, 白白消耗风控额度。这正是 #14 让断点跳过 none 的初衷。
diagnosis = missing
none
因此 none 只能通过 #15 提供的一次性重置工具、或主图变化来解除。
如果本次拉取发现 main_image 也变了,说明是另一张图, 旧的「搜不到」结论不再适用,理论上 video_status = 'none' 可以重置为 pending。
main_image
2026-09-03 负责人确认:本工单不做。 本工单只处理 video_diagnosis 由 ok 变 missing 这一条规则,主图变化不触发任何状态修改。 将来确有需要时另开工单。
internal/store/product.go
internal/store/video.go
预计修改文件:
product_test.go
video_test.go
app.go
video_status='none'
upload_status='done'
missing → ok
internal/
go vet ./... go build ./... go test ./internal/... -v go test ./... cd frontend && npx vite build
单元测试需覆盖:
missing → missing
真机验证(负责人执行):
git revert
负责人提出:「拉取数据入库时去检测视频子目录和文件在不在」。
本工单原本就是「全量拉取后按货憨憨最新状态修正本地工作流状态」, 磁盘对账是同一时机、同一目的(拉取后修正本地状态),并入本工单。
触发时机:「下载数据」全量拉取完成之后,作为独立的对账步骤。 不得写进 store.UpsertProducts——那是数据层,不应该知道 video_dir 的存在, 也不应该 stat 文件系统。对账放在 app.go,日志单独汇报补回条数。
store.UpsertProducts
video_dir
规则(只补不删):
<video_dir>/<蝦皮ID>/<蝦皮ID>_N.mp4
第二条必须克制:video_dir 是可配置的,指向移动硬盘未挂载、或使用者改了路径时, 扫描会看到「文件全没了」,此时删记录等于一次性抹掉全部历史。 缺文件的场景已由上传路径的「取第一个 downloaded 且文件真实存在」检查兜住。
downloaded
补回记录的残缺性必须如实标记:从磁盘只能还原 local_path 和 file_size, 还原不了 source_item(视频来自哪个淘宝同款),而那是负责人明确要求记库的信息。 补回记录的 source_item 只能留空,且要能与正常搜出来的记录区分开,不得冒充完整记录。
file_size
source_item
性能:目录名是确定的,一个商品一次 os.Stat,约 9300 个商品耗时可忽略, 不需要遍历搜索整个视频目录。
os.Stat
这不能替代根因修复:本次漂移的根因是 ReplaceVideos 先删后写,已另开 #18 修复。 对账是兜底,先写后删才是止血,两者都要做。
ReplaceVideos
依赖调整:本工单前置增加 #18。
No dependencies set.
The note is not visible to the blocked user.
基本信息
依赖与并行
子项目影响
原始需求
「我的想法是每次全量拉取,是否有视频的状态覆盖本地,如果上次上传了,被删除,
最新拉取是无视频,筛选出来就可以重新上传,你觉得合理吗」
要解决什么
现状
三个状态字段回答的是不同问题:
video_diagnosisvideo_statusupload_statusUpsertProducts已经在每次全量拉取时用货憨憨的video_diagnosis覆盖本地(
internal/store/product.go:118),前端「类型 = 缺少视频」筛的就是它。所以「视频被删 → 重新拉取 → 能筛出来」这条链路目前是通的。
问题
筛得出来,但跑起来什么也不会发生。
某商品此前已上传成功(
upload_status = 'done'),后来视频在上游被删除。重新全量拉取后
video_diagnosis变回missing,界面能筛出这个商品,但批量任务按
upload_status = 'done'判定为已完成,直接跳过它。期望结果
全量拉取发现某商品的视频在上游消失后,本地的工作流状态要随之修正,
使它能被重新处理;且已经下载到本地的视频直接重传,不重新搜淘宝。
做什么 / 不做什么
video_diagnosis由ok变为missing的商品upload_status或download_statusvideo_diagnosis = 'missing'就把video_status = 'none'重置为pending(原因见下,这是本工单最重要的边界)
已确认方案
触发时机
在
UpsertProducts写入过程中,对每条商品比较写入前的旧video_diagnosis与本次拉取的新值。只处理
ok → missing这一个方向。新增商品(本地原本不存在)不适用本规则,它们本来就是
pending。处理规则
ok → missing时:本地已有下载完成的视频(
videos表存在该商品status = 'downloaded'的记录,且
local_path指向的文件仍然存在):upload_status→pendingvideo_status和download_status本地没有可用视频:
download_status→pendingupload_status→pendingvideo_status保持原值不变(见下方边界说明)★ 边界:为什么不重置
video_status = 'none'★video_status = 'none'的含义是「我们拿这张主图去淘宝搜过,确实没有同款视频」。这个结论是关于商品主图的,不是关于货憨憨状态的——
货憨憨那边的视频被删,不会让淘宝突然多出一个同款视频。
若因
diagnosis = missing就把none重置为pending,会导致:货憨憨永远说缺视频 → 我们永远搜不到 → 每批任务都重新搜一遍,无限循环,
白白消耗风控额度。这正是 #14 让断点跳过
none的初衷。因此
none只能通过 #15 提供的一次性重置工具、或主图变化来解除。主图变化
如果本次拉取发现
main_image也变了,说明是另一张图,旧的「搜不到」结论不再适用,理论上
video_status = 'none'可以重置为pending。2026-09-03 负责人确认:本工单不做。 本工单只处理
video_diagnosis由
ok变missing这一条规则,主图变化不触发任何状态修改。将来确有需要时另开工单。
实现位置
internal/store/product.go:UpsertProducts内在同一事务中完成比较与状态修正,避免出现「诊断已更新但状态没跟上」的中间态
internal/store/video.go预计修改文件:
internal/store/product.go、product_test.gointernal/store/video.go、video_test.go(若需新增查询方法)app.go(下载数据完成后在运行日志中汇报「N 个商品的视频在上游消失,已退回待处理」)需求变化记录
video_status='none',本工单不做设计与原型门禁
筛选与列表沿用现有已确认的实现。
文档影响
video_diagnosis由货憨憨每次全量拉取覆盖、以及
ok → missing的状态修正规则和none不被重置的原因。交付文档影响
任务记录与可选快照
验收标准
upload_status='done',重新拉取后诊断变missing且本地有可用视频 →
upload_status变pending,video_status/download_status不变download_status与upload_status变pendingvideo_status='none'的商品在任何情况下都不被本规则重置missing不变(ok → missing之外的方向不触发任何状态修改)missing → ok时不做任何状态修改internal/下不得 import wails验证方式
单元测试需覆盖:
ok → missing+ 本地有视频 → 只重置upload_statusok → missing+ 本地无视频 → 重置download_status和upload_statusok → missing+video_status='none'→none不被重置missing → ok→ 无任何状态修改missing → missing→ 无任何状态修改真机验证(负责人执行):
upload_status回到待处理,且能被重新处理风险和回退
UpsertProducts里,而「下载数据」会处理近万条商品。逐条查
videos表会显著拖慢。缓解:先批量查出ok → missing的商品 ID(通常极少),再只对这批查视频,不要每条都查。
消耗大量风控额度。缓解:只处理
ok → missing单一方向;验收标准里对每个不该触发的方向都写了断言。
internal/store/product.go,git revert即可。不新增列、不改结构,回退后数据无残留。
范围扩充:拉取后增加本地视频磁盘对账(2026-09-03)
负责人提出:「拉取数据入库时去检测视频子目录和文件在不在」。
本工单原本就是「全量拉取后按货憨憨最新状态修正本地工作流状态」,
磁盘对账是同一时机、同一目的(拉取后修正本地状态),并入本工单。
触发时机:「下载数据」全量拉取完成之后,作为独立的对账步骤。
不得写进
store.UpsertProducts——那是数据层,不应该知道video_dir的存在,也不应该 stat 文件系统。对账放在
app.go,日志单独汇报补回条数。规则(只补不删):
<video_dir>/<蝦皮ID>/<蝦皮ID>_N.mp4,videos表无对应记录videos表有记录,磁盘上文件不存在第二条必须克制:
video_dir是可配置的,指向移动硬盘未挂载、或使用者改了路径时,扫描会看到「文件全没了」,此时删记录等于一次性抹掉全部历史。
缺文件的场景已由上传路径的「取第一个
downloaded且文件真实存在」检查兜住。补回记录的残缺性必须如实标记:从磁盘只能还原
local_path和file_size,还原不了
source_item(视频来自哪个淘宝同款),而那是负责人明确要求记库的信息。补回记录的
source_item只能留空,且要能与正常搜出来的记录区分开,不得冒充完整记录。性能:目录名是确定的,一个商品一次
os.Stat,约 9300 个商品耗时可忽略,不需要遍历搜索整个视频目录。
这不能替代根因修复:本次漂移的根因是
ReplaceVideos先删后写,已另开 #18 修复。对账是兜底,先写后删才是止血,两者都要做。
依赖调整:本工单前置增加 #18。