fix: 上传素材后视频库立即显示(创建 PROCESSING 状态 Asset) #1644
Reference in New Issue
Block a user
Delete Branch "fix/upload-asset-not-visible-v2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
问题
上传视频/图片素材后,前端视频库页面不会立即显示新素材。需要手动刷新才能看到。
根因
/upload/direct/complete和upload_asset端点只创建 IngestJob 记录并派发 Celery 任务。Asset 记录由 worker 异步创建。前端上传完成后 invalidate query 刷新列表时,新素材还不存在于数据库中。修复
Asset(status=PROCESSING)记录,前端刷新后即可看到(显示为"处理中")find_by_storage_key找到已有 Asset 记录,更新元数据(时长、分辨率、编码等)+ 状态改为 READY改动文件
apps/api/app/api/routes/upload.py:添加_infer_mime_type_from_storage_key+_create_pending_assetapps/worker/worker_app/tasks/ingest.py:先查找已有 Asset,有则更新,无则创建packages/ports/asset_repository.py:新增find_by_storage_key抽象方法packages/adapters/in_memory/asset_repository.py:实现find_by_storage_keypackages/adapters/sqlalchemy_impl/asset_repository.py:实现find_by_storage_keytests/unit/test_form_upload_routes.py:更新测试 mock注:此 PR 替换原 #1642(base 分支从 main 改为 develop)
🚀 预览环境已部署
代码审查结果 - PR #1644
【阻塞级判定】
📊 审查概览
🔴 阻塞级问题(必须修复)
[apps/worker/worker_app/tasks/ingest.py:661] 异常捕获过于宽泛导致数据重复风险
find_by_storage_key外部使用了裸的except Exception。如果数据库查询抛出异常(如网络抖动、超时),代码会捕获异常并继续执行,导致existing_asset为None,进而触发“创建新 Asset”的逻辑。这会导致同一个storage_key对应多条 Asset 记录(一条由 API 创建的 PROCESSING 状态,一条由 Worker 创建的 READY 状态),造成数据重复。find_by_storage_key可能不存在(旧版本兼容),应捕获NotImplementedError或特定异常;对于数据库连接等异常,应该向上抛出让任务重试,而不是静默失败并创建脏数据。[apps/api/app/api/routes/upload.py:244] 缺少去重检查导致数据一致性风险
_create_pending_asset中直接创建 Asset 记录,未先检查file_hash是否已存在。如果用户重复上传相同文件,会创建新的 Asset 记录。如果数据库有唯一索引约束,这里会直接报错导致 500;如果没有约束,则会生成重复的素材记录,破坏业务去重逻辑。_create_pending_asset之前,必须调用asset_repository.find_by_library_and_file_hash检查文件是否已存在。如果存在,应直接返回已有的 Asset ID 或抛出 409 冲突错误,而不是创建新记录。[packages/adapters/sqlalchemy_impl/asset_repository.py:429] 字段映射逻辑错误导致查询失效
find_by_storage_key实现中,使用AssetModel.file_url == storage_key进行查询。通常storage_key是对象存储的路径(如uploads/a.mp4),而file_url往往是完整的访问地址(如https://bucket.oss.com/uploads/a.mp4)。如果两者格式不一致,该查询将永远返回None,导致 Worker 无法更新 API 创建的记录,而是创建新的重复记录。AssetModel.file_url存储的是纯 Key 还是完整 URL。如果是完整 URL,应修改查询逻辑(例如使用.endswith(storage_key)或确保存入时只存 Key)。目前的实现存在极高的逻辑隐患。💡 改进建议(不阻塞合并)
[apps/api/app/api/routes/upload.py:89] 默认 MIME 类型设置不当
_infer_mime_type_from_storage_key函数在无法识别后缀时默认返回"video/mp4"。如果用户上传了系统不支持的后缀文件(如 .psd, .doc),会被错误标记为视频,可能导致前端播放器尝试加载非视频文件而报错。建议默认返回"application/octet-stream"或抛出错误。[apps/worker/worker_app/tasks/ingest.py:680] 领域模型直接修改属性
asset.mime_type = ...等方式修改领域对象属性。如果Asset是富领域模型,建议封装update_metadata或mark_as_ready等方法来保证状态流转的一致性和业务逻辑封装。✅ 良好实践
AssetRepository端口中新增抽象方法,并同步更新了所有实现类(SQLAlchemy 和 InMemory),符合开闭原则。✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能无明显问题
🤖 由 AI 代码审查机器人自动生成 | 2026-09-03 06:50:01 | 模型:
CI全绿,自动审批通过。
CI全绿,自动审批通过。
🗑️ 预览环境已清理
PR #1644 已关闭或合并,对应的预览环境已被清理。