feat(render3d): 每个 3D 资产最多 3 个动作(本期试用限额) - #836
Conversation
本期试用限额,不是成本限制 —— 三渲二的动作由浏览器出帧,对我们几乎零成本。 作用域取"每个 3D 资产"而不是"每个用户":动作是从模型生成出来的,换个模型就是另一批 动作;按用户总数算的话,建了第二个模型却分不到名额。要改成按用户总数,换掉统计范围即可。 闸放在 HTTP 边界:任务还没建、积分还没冻,拒起来干净;走到执行阶段才失败的话,用户看到 的是通用的"生成失败",不知道是撞了限额。 只管三渲二:没有 3D 资产的造型走 i2v,那条路线有自己的成本与限额,在这里被拒的话用户会 被一个跟他无关的限额挡住。character_data 解析失败时放行 —— 与 _outfit_model_3d_url 同一个取舍:放行只是少拦一次,拦错是把用户卡死且看不出原因。 Closes 1024XEngineer#829
|
Deployment failed for project windup with the following error: Learn More: https://vercel.com/huyan-s-projects1?upgradeToPro=build-rate-limit |
There was a problem hiding this comment.
审阅了三渲二动作限额的 HTTP 路由、任务创建生命周期,以及新增的边界用例。路由判据(仅 3D 造型、未知造型与脏数据处理)与 Issue 约定一致;但当前计数没有覆盖尚未回填到 character_data 的动作任务,因此上限可以被绕过。建议在提交边界对进行中的 3D 动作做原子预留/计数,或将其纳入同一事务的限额判断。
验证:已检查固定 SHA diff、调用方与结果回填契约;尝试运行 uv run pytest tests/test_render3d_action_cap.py tests/test_render3d_route_and_assets.py -q,但当前环境没有安装 uv。
| outfit = next((o for o in data.outfits if o.id == outfit_id), None) | ||
| if outfit is None or not (outfit.model_3d_url or "").strip(): | ||
| return # 没有 3D 资产 = 走 i2v,不归本闸管 | ||
| if len(outfit.actions) >= MAX_ACTIONS_PER_3D_ASSET: |
There was a problem hiding this comment.
[P1] Reserve pending 3D action submissions before counting
len(outfit.actions) 只统计已经写回 character_data 的动作,但 /generation/action 这里只创建 PENDING 任务;按当前契约,CharacterActionOutput 是任务完成后由前端再写入 outfits[].actions[]。因此当资产有 0、1 或 2 个已保存动作时,可以连续/并发提交任意多个请求,每个请求都会在这个检查看到同一个旧计数并成功创建任务,最终超过“每个资产最多 3 个动作”。请在 HTTP 提交事务中原子预留名额(或把该资产的未完成 3D 动作任务纳入带锁的计数),再创建任务。
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #836 +/- ##
========================================
Coverage 86.47% 86.47%
========================================
Files 296 296
Lines 22136 22309 +173
Branches 3356 3383 +27
========================================
+ Hits 19142 19292 +150
- Misses 2055 2073 +18
- Partials 939 944 +5
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 13 files with indirect coverage changes 🚀 New features to boost your workflow:
|
本期三渲二试用限额:每个 3D 资产最多 3 个动作。与已有的
MAX_ASSETS_PER_USER = 2(#771 已合)配套。作用域取「每个资产」而不是「每个用户」
动作是从模型生成出来的,换个模型就是另一批动作。按用户总数算的话,建了第二个模型却分不到名额。常量单列,要改成按用户总数是换掉统计范围的事。
只管三渲二
没有 3D 资产的造型走 i2v,那条路线有自己的成本与限额。在这个闸里被拒的话,用户会被一个跟他无关的限额挡住,而且看不出原因。判据与
_outfit_model_3d_url一致:没有outfit_id、或该造型没有model_3d_url,都不归本闸管。闸放在 HTTP 边界:任务还没建、积分还没冻,拒起来干净;走到执行阶段才失败的话,用户看到的是通用的「生成失败」,不知道是撞了限额。
character_data解析失败时放行 —— 与_outfit_model_3d_url同一个取舍:放行只是少拦一次,拦错是把用户卡死且看不出原因。Verification
outfit_id也拦、脏数据把用户卡死、未知造型在两处各报一次(先跑的那个决定用户看到哪句话,而这里那句是错的)。if False后用例会红;还原后核对 sha256 一致。action_type(真名是type)、缺frame_count,model_validate失败被「脏数据放行」那条兜住,用例明明在测上限却什么都没测到。已在注释里记下。uv run ruff check ./export_openapirc=0 无漂移 /lint-imports2 kept 0 broken /pytest1852 passed, 0 failed。Closes #829