同步完美像素端点的并发与预算文档
补齐端点级并发闸、等待队列与 503/504 的契约描述 修正 30 秒预算的覆盖范围为自请求入口起算 记录超时预检与有界队列计数的两条踩坑 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4587,7 +4587,7 @@
|
||||
## 2026-07-30 已有静态图片增加免费一键完美像素化
|
||||
|
||||
- UI 决策:图片选中浮动工具栏的栅格处理顺序固定为 `裁扩 → 去除背景 → 完美像素`。完美像素只对当前活动的静态栅格图层一键执行,不打开参数面板;音频、视频、图片序列和 `character-animation` 不显示。请求期间按 layer id 禁用并显示 busy,首个 await 前用同步 ref 防双击重复提交;结果保留源图并在右侧新增同尺寸 PNG。
|
||||
- API 与执行边界:新增登录态 `POST /api/editor/images/pixel-art-snaps`,复用 `platform-image` 纯内存 snapper、进程级并发 2、30 秒排队加处理总预算以及既有输入尺寸上限。该入口免费 inline,不调用外部 provider,不创建 `external_generation_job`,不打开或刷新任务侧栏,也不进入泥点扣费 / 退款;它与生成请求 `style="pixelArt"` 的 best-effort 后处理是两个契约。
|
||||
- API 与执行边界:新增登录态 `POST /api/editor/images/pixel-art-snaps`,复用 `platform-image` 纯内存 snapper、进程级 CPU 并发 2 以及既有输入尺寸上限。该入口免费 inline,不调用外部 provider,不创建 `external_generation_job`,不打开或刷新任务侧栏,也不进入泥点扣费 / 退款;它与生成请求 `style="pixelArt"` 的 best-effort 后处理是两个契约。2026-07-31 修订:并发控制改为两层——端点级并发闸最大 4、等待队列上限 2048,必须在首次 IO 之前取得,队列满返回 `503` 并带 `Retry-After`,等待超预算返回 `504`;内层仍是共享的 CPU 并发 2。30 秒预算的起算点同时从「下载完成后」前移到 handler 入口,现在覆盖归属校验的 SpacetimeDB 读取、OSS 下载、两层排队与规整全过程,而不再只是 CPU 排队加处理。该端点的 OSS 读写共用带 `connect 10s / total 120s` 的进程级 HTTP 客户端,不再每次新建无超时客户端。
|
||||
- 媒体与归属:前端先创建关闭 composer 的右侧占位,再解析或上传源图以取得稳定引用,随后 flush 包含该占位的当前项目布局;正式请求使用 `sourceImageSrc` 承载源图 `objectKey / resourceId / assetId` 候选稳定引用,`projectId / canvasCompletion` 必填且 `canvasCompletion.dialogId` 必须非空,并可携带 `sourceResourceId / assetKind / generationInputs / assetFolderId / assetLabel`。请求禁止 `data:` / `blob:`、signed URL 和普通外链。BFF 下载前必须将候选解析为当前 owner 已登记的私有 OSS object key,并校验 project / resource / asset 归属。
|
||||
- 失败与持久化:已有图片入口使用 strict 语义,只接受静态 PNG / JPEG / WebP,拒绝 GIF、APNG、动画 WebP 和非静态素材。strict 完全复用生成风格的 legacy profile、峰值估算、单轴步长补全、walker、采样与编码;唯一差异是横纵两轴都未检测到步长时,不执行 `min(width,height)/64` 统一网格兜底而返回不适用。任一轴已检测到步长时,strict 与 legacy 行为及输出必须一致。读取、解码、输入校验、并发排队、像素规整或 PNG 编码失败 / 超时 / 不适用时,不保存原图副本冒充成功,不执行最终 OSS PUT,也不创建 asset object、project resource、账号素材或结果 layer。成功时只对最终 PNG 做一次 PUT,至多各创建一个 `editor_project_resource` 和一个 `editor_asset`;源图已有正式 project resource 时,结果以 `source_resource_id` 关联该资源,再由 `canvasCompletion` 写入至多一个右侧派生 layer;不保存逻辑低分辨率图、诊断图或前后对比图。
|
||||
- 非事务边界:strict 零写入只覆盖首个最终 PNG PUT 前的引用 / owner / 项目 / 类型 / 静态编码 / 元数据 / 网格适用性 / CPU 处理门禁。进入持久化后沿用现有 `OSS + asset object → project resource → editor asset → canvas completion` 非事务顺序,后段失败可能保留此前已确认对象或记录;不做删除补偿或 unsafe POST 自动重放,按 `task_id / object_key / resource_id` 读取权威快照排障,跨系统单事务留待独立 procedure 方案。
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
- 关联:相关文件、文档、提交或 Issue
|
||||
```
|
||||
|
||||
## `timeout_at` 不能替代显式的预算耗尽预检
|
||||
|
||||
- 现象:给完美像素加端点级并发闸后,预算已经耗尽的请求仍然能拿到许可,白占一个名额继续去打几轮全账号 SpacetimeDB 扫描,直到下载那步才失败。
|
||||
- 原因:`tokio::time::timeout_at` 会先 poll 一次内层 future 再判超时。信号量有空闲许可时 `acquire_owned()` 首次 poll 就绪,于是即使 deadline 早已过去,返回的仍是 `Ok(Ok(permit))` 而不是超时。既有 `acquire_editor_pixel_art_cpu_permit` 里那句 `if Instant::now() >= processing_deadline` 正是为此存在,新写的许可函数漏掉后被单测抓出。
|
||||
- 处理:所有「先判预算、再等资源」的获取函数都必须在 `timeout_at` 之前显式判一次 `Instant::now() >= deadline` 并直接返回超时错误;这句不是冗余防御。同理,进入排队计数之前也要先做这个预检,避免为注定失败的请求占用队列名额。
|
||||
- 验证:用已过期的 deadline 调用获取函数,断言返回 `504` 而不是许可;同时断言队列深度计数回到 0。仅靠「信号量占满时超时」的用例发现不了,必须在**有空闲许可**的状态下测。
|
||||
- 关联:`server-rs/crates/api-server/src/editor_project.rs`(`acquire_editor_pixel_art_snap_permit`、`acquire_editor_pixel_art_cpu_permit`)。
|
||||
|
||||
## 有界等待队列的计数递减必须写在 Drop 里
|
||||
|
||||
- 现象:给同步端点加「最多 N 个等待者」的保险丝时,若把计数递减写在正常返回路径上,客户端断连或超时触发会让等待中的 future 被丢弃而跳过递减;计数只增不减,最终队列永久判定为满,接口对所有人返回 `503` 且不会自愈。
|
||||
- 原因:Rust 的 async future 可以在任意 await 点被取消,取消时只保证 `Drop` 会跑,不保证后续代码会执行。有界队列的入场与离场天然不对称。
|
||||
- 处理:把递增封进一个 guard 结构体,递减放在它的 `Drop` 实现里;递增本身用 `fetch_update` 的 CAS,不能用「先读后加」——两个线程同时读到 `max - 1` 各自加一就会越界。拿到资源后立即 `drop(guard)` 让出队列名额,不要让它跟着许可一起活到请求结束。
|
||||
- 验证:单测覆盖 CAS 边界(满了返回失败且计数不越界、上限为 0 时任何进入都失败)、guard 离开作用域后计数归零、以及失败路径(预算耗尽、获取超时)也归还名额。
|
||||
- 关联:`server-rs/crates/api-server/src/editor_project.rs`(`try_enter_bounded_queue`、`EditorPixelArtSnapQueueGuard`)。
|
||||
|
||||
## 图集切片上限必须早于合并、裁剪和编码
|
||||
|
||||
- 现象:透明图集含大量独立碎块或噪点时,接口长时间占用 async worker;最终即使报“超过 64 个切片”,此前仍已完成全量两两合并、裁剪和 PNG 编码。
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
- 像素模式的持久化增量必须为零:普通图片仍只上传原有一张最终主图;角色仍只保留原有 provider 原图与透明主图;图标仍只保留原有 provider 原图、透明图集和实际成功的切片。禁止保存逻辑低分辨率图、像素化前后双份主图、预览图、网格诊断图或报告,禁止新增 asset / resource 类型、项目资源、画布 item、队列 job kind 或数据库字段。
|
||||
- 像素后处理属于 best-effort:失败时保留进入该步骤前的图片,继续原有最终上传与画布完成,并通过既有通用 `warning` 返回非阻断原因,不把任务改为失败或退款。BgFilter 自身失败时仍按原 source-only fallback 收口,像素处理不运行;图标后处理成功后再执行原有自动拆分,拆分告警继续使用现有 `sliceWarning` 语义。
|
||||
- 选中已有静态栅格图层后的 `完美像素` 是独立的一键派生操作,不等同于生成请求上的 `style="pixelArt"`。它不打开参数面板,只处理当前活动图层,保留源图,并在源图右侧创建同尺寸 PNG 派生结果;音频、视频、图片序列和 `character-animation` 不显示该按钮。
|
||||
- 已有图片像素规整固定调用登录态同源 `POST /api/editor/images/pixel-art-snaps`,复用同一纯内存 Rust snapper、并发许可、输入尺寸上限和 30 秒 CPU 总预算。该入口免费、只走当前 HTTP 请求内的 inline 处理,不创建 `external_generation_job`,不刷新或自动打开任务侧栏,也不进入泥点扣费 / 退款链路。
|
||||
- 已有图片像素规整固定调用登录态同源 `POST /api/editor/images/pixel-art-snaps`,复用同一纯内存 Rust snapper、CPU 并发许可和输入尺寸上限。该入口免费、只走当前 HTTP 请求内的 inline 处理,不创建 `external_generation_job`,不刷新或自动打开任务侧栏,也不进入泥点扣费 / 退款链路。它另有一层端点级并发闸(最大 4、等待队列上限 2048),设在首次 IO 之前;队列满返回 `503` 并带 `Retry-After`,等待超预算返回 `504`。30 秒总预算从 handler 入口起算,覆盖归属校验的 SpacetimeDB 读取、OSS 下载、两层排队与规整,不是只算 CPU 部分。
|
||||
- 前端提交前先创建关闭 composer 的右侧生成占位,再解析或上传源图以取得稳定引用,随后 flush 包含该占位的当前项目布局,最后把承载稳定候选引用的 `sourceImageSrc`、必填 `projectId / canvasCompletion`(其中 `canvasCompletion.dialogId` 必须非空)以及可选 `sourceResourceId / assetFolderId / assetLabel` 一次提交。`sourceImageSrc` 优先由当前图层已有的 `objectKey / resourceId / sourceAssetId` 解析;尚未登记的浏览器本地图片必须先上传,正式请求不得包含 `data:` / `blob:`、signed URL 或普通外链。后端在读取源图前必须把该字段解析为当前 owner 已登记的私有 OSS object key,并核对 project / resource / asset 归属。
|
||||
- 该已有图片入口使用 strict 语义:只接受静态 PNG / JPEG / WebP,GIF、APNG、动画 WebP、图片序列及其它非静态媒体必须在处理前拒绝。strict 与生成风格复用完全相同的 legacy profile、峰值估算、单轴步长补全、walker、采样和编码;仅当横纵两轴都未检测到步长、legacy 即将使用 `min(width,height)/64` 统一网格兜底时拒绝。任一轴已检测到步长时,两条路径行为和输出必须一致。源图读取、解码、尺寸校验、排队、像素规整或 PNG 编码任一步失败 / 超时 / 不适用时,请求失败,不保留原图副本冒充成功,不执行最终 OSS PUT,也不创建 project resource、账号素材或结果图层。成功时只对最终 PNG 执行一次 OSS PUT,并至多各创建一个 `editor_project_resource` 和一个 `editor_asset`,再按 `canvasCompletion` 写回一个派生图层;不得保存逻辑低分辨率图、诊断图或前后对比图。
|
||||
- strict 的零写入边界截至首个最终 PNG PUT:所有可预判的引用、归属、类型、静态编码、元数据、网格适用性和 CPU 处理错误必须在此前失败。进入 OSS / SpacetimeDB 持久化后沿用现有非事务顺序,后段 resource / asset / completion 失败可能保留此前已确认对象或记录;客户端不做自动重放或删除补偿,而是按 `taskId / objectKey / resourceId` 重新读取项目和素材快照。
|
||||
|
||||
@@ -248,7 +248,7 @@ npm run check:server-rs-ddd
|
||||
|
||||
## 外部服务与资产
|
||||
|
||||
- 已有图片完美像素化:登录态 `POST /api/editor/images/pixel-art-snaps` 使用 `sourceImageSrc` 承载 `objectKey / resourceId / assetId` 候选稳定引用,要求 `projectId / canvasCompletion` 且 `canvasCompletion.dialogId` 必须非空,并可携带 `sourceResourceId / assetKind / generationInputs / assetFolderId / assetLabel`;BFF 必须在下载前将候选解析为当前 owner 已登记的私有 OSS object key,并校验 project / resource / asset 归属,拒绝 `data:` / `blob:`、signed URL、普通外链和音频、视频、图片序列等非静态栅格输入。编码门禁只接受静态 PNG / JPEG / WebP,明确拒绝 GIF、带 `acTL` 的 APNG 及带动画标志 / `ANIM` / `ANMF` chunk 的 WebP。处理复用 `platform-image` 纯内存 snapper、进程级并发 `2`、30 秒排队加处理总预算、单边 `10000` 与总像素 `8294400` 上限;strict 与生成风格使用完全相同的 legacy profile、峰值估算、单轴步长补全、walker、采样和编码,唯一差异是横纵两轴都未检测到步长时,不执行 `min(width,height)/64` 统一网格兜底而返回不适用。任一轴已检测到步长时,两条路径行为和输出必须一致。读取、解码、校验、排队、规整、PNG 编码任一步失败 / 超时 / 不适用时,在最终持久化前返回错误,OSS PUT、asset object、project resource、账号素材和画布 layer 增量都必须为零。成功结果保留源图,只对最终 PNG 做一次 OSS PUT,并至多各创建一个 `editor_project_resource` 和一个 `editor_asset`;源图已有正式 project resource 时,结果资源以 `source_resource_id` 关联该资源,再按 `canvasCompletion` 尝试写入一个右侧派生 layer。completion 读取的权威 dialog 已删除时沿用现有语义跳过画布写入,不得用请求中的旧 placeholder 复活图层;已经成功落库的 resource / asset 可以保留。客户端回包时若本地 dialog 已删除,不应用完成快照;现有布局 CAS 没有 deletion tombstone,completion 先提交、删除保存后冲突的极端竞态仍按权威快照收口。客户端不得为该 unsafe POST 配置 `EDITOR_REQUEST_RETRY_OPTIONS`,请求字节可能已发送后不因 transport 异常或 `408 / 425 / 429 / 502 / 503 / 504` 自动重放;Bearer 中间件在 handler 前拒绝请求后的既有认证恢复继续保留。结果未知时先 GET 权威项目 / 素材快照。
|
||||
- 已有图片完美像素化:登录态 `POST /api/editor/images/pixel-art-snaps` 使用 `sourceImageSrc` 承载 `objectKey / resourceId / assetId` 候选稳定引用,要求 `projectId / canvasCompletion` 且 `canvasCompletion.dialogId` 必须非空,并可携带 `sourceResourceId / assetKind / generationInputs / assetFolderId / assetLabel`;BFF 必须在下载前将候选解析为当前 owner 已登记的私有 OSS object key,并校验 project / resource / asset 归属,拒绝 `data:` / `blob:`、signed URL、普通外链和音频、视频、图片序列等非静态栅格输入。编码门禁只接受静态 PNG / JPEG / WebP,明确拒绝 GIF、带 `acTL` 的 APNG 及带动画标志 / `ANIM` / `ANMF` chunk 的 WebP。处理复用 `platform-image` 纯内存 snapper、单边 `10000` 与总像素 `8294400` 上限,并发控制分两层:端点级并发闸最大 `4`、等待队列上限 `2048`,在首次 IO 之前取得,队列满返回 `503` 并带 `Retry-After`,等待超预算返回 `504`;内层是与生成风格共享的进程级 CPU 并发 `2`。30 秒总预算从 handler 入口起算,覆盖归属校验读取、OSS 下载、两层排队与规整全过程。OSS 读写共用带 `connect 10s / total 120s` 的进程级 HTTP 客户端。strict 与生成风格使用完全相同的 legacy profile、峰值估算、单轴步长补全、walker、采样和编码,唯一差异是横纵两轴都未检测到步长时,不执行 `min(width,height)/64` 统一网格兜底而返回不适用。任一轴已检测到步长时,两条路径行为和输出必须一致。读取、解码、校验、排队、规整、PNG 编码任一步失败 / 超时 / 不适用时,在最终持久化前返回错误,OSS PUT、asset object、project resource、账号素材和画布 layer 增量都必须为零。成功结果保留源图,只对最终 PNG 做一次 OSS PUT,并至多各创建一个 `editor_project_resource` 和一个 `editor_asset`;源图已有正式 project resource 时,结果资源以 `source_resource_id` 关联该资源,再按 `canvasCompletion` 尝试写入一个右侧派生 layer。completion 读取的权威 dialog 已删除时沿用现有语义跳过画布写入,不得用请求中的旧 placeholder 复活图层;已经成功落库的 resource / asset 可以保留。客户端回包时若本地 dialog 已删除,不应用完成快照;现有布局 CAS 没有 deletion tombstone,completion 先提交、删除保存后冲突的极端竞态仍按权威快照收口。客户端不得为该 unsafe POST 配置 `EDITOR_REQUEST_RETRY_OPTIONS`,请求字节可能已发送后不因 transport 异常或 `408 / 425 / 429 / 502 / 503 / 504` 自动重放;Bearer 中间件在 handler 前拒绝请求后的既有认证恢复继续保留。结果未知时先 GET 权威项目 / 素材快照。
|
||||
- 完美像素持久化边界:所有可判定的稳定引用、owner、项目、来源资源、素材类型、静态编码、元数据、网格适用性、排队、CPU、解码、规整和编码校验都必须在首个最终 PNG PUT 前完成。进入持久化后沿用既有跨 OSS 与 SpacetimeDB 的非事务边界,依次确认 PNG / asset object、project resource、账号素材和 completion;后段失败可能保留此前已经确认的对象或记录,不做破坏性删除补偿,也不自动重放 unsafe POST。排障按响应或日志中的 `task_id / object_key / resource_id` 重新读取权威项目与素材快照;跨系统单事务 completion 留待独立 procedure 方案收口。
|
||||
- LLM:通用 LLM 门面继续使用 `GENARRATIVE_LLM_*`;创意 Agent `gpt-5.4-mini` Chat Completions 文本链路已于 2026-06 从 APIMart 迁移到 VectorEngine,使用 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 构造 OpenAI-compatible client,`api-server` 会把未带 `/v1` 的 VectorEngine base URL 规范化到 `/v1` 后请求 `/chat/completions`。通用 `/api/llm/chat/completions` 代理使用 `GENARRATIVE_LLM_PROVIDER=openai-compatible`、`GENARRATIVE_LLM_BASE_URL=https://api.vectorengine.cn/v1`、`GENARRATIVE_LLM_MODEL=gpt-5.4-mini`;未单独配置 `GENARRATIVE_LLM_API_KEY` 时可复用 `VECTOR_ENGINE_API_KEY`。`APIMART_BASE_URL` / `APIMART_API_KEY` 只作为历史残留,不再作为创意 Agent gpt-5.4-mini 客户端来源;后续排障时优先确认 VectorEngine `/v1/models`、`/v1/chat/completions` 和 `/v1/responses` 可用性。
|
||||
- 图片生成:VectorEngine 图片 provider 归属 `platform-image`,密钥只在后端环境变量中;逻辑 SKU 与 provider 首选模型均固定为 `gpt-image-2`,只在明确模型不可用、408 / 非拒绝类 429 / 5xx、响应解析失败或非拒绝类缺图时切换兜底模型 `gpt-image-2-c`。401 / 403、普通参数或安全拒绝、本地配置 / 参考图错误、无法确认上游是否已受理的发送错误、request budget 耗尽和生成成功后的图片下载失败不得切模型。一次业务请求总发送上限仍为 5 次;切换兜底模型会消耗后续 attempt,不允许两个模型各重试 5 次。`api-server` 内的 `openai_image_generation.rs` 只是兼容调用面和外部失败审计桥接,不再承载 provider 协议实现。实际外部生成运行记录统一落 `tracking_event`,`event_key = external_generation_run`,metadata 记录开始 / 结束时间、耗时、状态、成功标记、失败原因、provider task id、结果摘要和 recovered failure 数量;首选模型失败但兜底模型成功时,首选失败仍落 `external_api_call_failure`。DashScope 只按仍在使用的历史能力单独处理,不作为 GPT-image-2 兜底。VectorEngine `/v1/images/generations` 和 `/v1/images/edits` 上游 POST 使用 `libcurl` 发送;`reqwest` 只保留给参考图 URL 下载和响应中图片 URL 下载。`/v1/images/edits` 的 multipart 参考图必须作为 libcurl 文件上传 part 发送,字段名为 `image`,实现上使用 `Form::buffer(file_name, bytes)` 并设置 `Content-Type`;不能只用 `contents(...).filename(...)`,否则上游会把请求转码为缺少图片并返回 `image is required`。`request_send` 阶段的 curl timeout / connect error 按可重试传输错误处理,最多尝试 5 次,并使用指数退避加短抖动;排障时优先看 `attempt`、`max_attempts`、`retry_delay_ms`、`fallback_from_model`、`fallback_to_model`、`reference_image_bytes_total` 和 `request_params`,不要把 `SendRequest` 当成上游业务错误。
|
||||
|
||||
@@ -65,7 +65,7 @@ worker 完成生成任务时,本次先用读取时 revision 调用 CAS 保存
|
||||
|
||||
`POST /api/editor/images/pixel-art-snaps` 的完美像素化不是 external job completion:它免费、在当前 HTTP 请求内 inline 执行,不创建任务行,也没有 `job_id / worker_id / lease_token`。前端仍须先创建关闭 composer 的右侧 generation dialog,再解析或上传源图以取得稳定引用,随后 flush 包含该占位的当前布局,最后把稳定源媒体引用和带非空 `dialogId` 的 `canvasCompletion` 一次提交;结构化 / legacy canvas 的完成分流继续由后端决定,前端不能直接写表或本地补造正式 layer。
|
||||
|
||||
像素读取、静态 PNG / JPEG / WebP 编码门禁、解码、输入限制、legacy 网格步长估算、并发排队、规整和 PNG 编码全部发生在持久化前。strict 与生成风格使用同一 profile、峰值估算、单轴步长补全、walker、采样和编码;仅在横纵两轴都未检测到步长、legacy 即将进入统一网格兜底时拒绝,任一轴已检测到步长时行为和输出完全一致。任一步失败、超时或不适用时不执行最终 OSS PUT,不创建 asset object、`editor_project_resource`、`editor_asset` 或结果 layer;不得保存原图副本、逻辑低分辨率图、诊断图或前后对比图冒充结果。处理成功时只 PUT 一张最终 PNG,并至多各创建一个 project resource 和一个账号素材;源图已有正式 project resource 时,结果资源的 `source_resource_id` 指向该资源。
|
||||
端点级并发排队、像素读取、静态 PNG / JPEG / WebP 编码门禁、解码、输入限制、legacy 网格步长估算、CPU 并发排队、规整和 PNG 编码全部发生在持久化前。两层排队的位置不同:端点级闸在首次 IO 之前,因此队列满的 `503` 早于任何 SpacetimeDB 读取和 OSS 下载返回;CPU 排队仍在下载之后、规整之前,等待超预算返回 `504`。两者都在持久化前失败,零写入结论不变。strict 与生成风格使用同一 profile、峰值估算、单轴步长补全、walker、采样和编码;仅在横纵两轴都未检测到步长、legacy 即将进入统一网格兜底时拒绝,任一轴已检测到步长时行为和输出完全一致。任一步失败、超时或不适用时不执行最终 OSS PUT,不创建 asset object、`editor_project_resource`、`editor_asset` 或结果 layer;不得保存原图副本、逻辑低分辨率图、诊断图或前后对比图冒充结果。处理成功时只 PUT 一张最终 PNG,并至多各创建一个 project resource 和一个账号素材;源图已有正式 project resource 时,结果资源的 `source_resource_id` 指向该资源。
|
||||
|
||||
该零写入保证只覆盖首个最终 PNG PUT 前的可预判与处理阶段。进入持久化后,PNG / asset object、project resource、账号素材与 canvas completion 仍跨 OSS 和多个 SpacetimeDB procedure,沿用既有非事务顺序;后段失败可以保留此前已经确认的对象或记录,不做自动删除补偿,也不由客户端重放请求。调用方应按 `task_id / object_key / resource_id` 重新读取权威项目和素材快照后显式收口。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user