修复 inline 路径修复性回读缺少绝对 deadline
上一轮把修复性回读绑到外层 request_deadline,但 with_external_call_deadline 只在队列 worker 与 openai_image_generation 两处调用,inline HTTP 请求的 RequestContext 默认 external_call_deadline=None,于是 download_deadline 传下去 仍是 None,走无界 download.await——该修复实际只对队列模式生效。 守卫改为在 request_deadline 缺失时自行以 Instant::now() + EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION 重新计时派生上界,两种模式下都不再 出现无界 GET。结构断言同时要求出现 unwrap_or_else 兜底与该常量。 同时修正决策记录里「最多增加一次 OSS GET」的措辞:约束是不重复读取已成功 取得的对象,而非整个请求至多一次 GET;第一次回读失败或被像素预算掐断时 允许第二次也是最后一次尝试,不视为违规。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,9 @@
|
||||
- 影响范围:`server-rs/crates/api-server/src/editor_project.rs` 的角色与图标像素规整降级路径;不改变成功路径、OSS PUT 次数、资源类型、画布项或前端契约,OSS GET 仍只在尺寸漂移时发生。
|
||||
- 验证方式:`pixel_art_degrade_paths_guard_postprocessed_delivery_dimensions` 结构断言固定"降级分支不得返回 `(postprocessed, None, …)`"与守卫的委托实现;运行 `cargo test -p api-server editor_project --manifest-path server-rs/Cargo.toml`、`npm run check:rustfmt`、`npm run check:encoding` 和 `git diff --check`。
|
||||
- 关联文档:本文件「2026-07-29 角色带背景原图与透明图统一交付尺寸」与「2026-07-28 图片生成风格使用可扩展字段并以纯内存像素规整首发」。
|
||||
- 补充(同日):守卫的回读必须分两类处理,否则会把「最多增加一次 OSS GET」放大成两次、且第二次无界。已取得 provider 原图的四条降级分支(permit 获取失败、worker 内 deadline、join 异常、worker 超时)改走纯内存守卫 `degrade_editor_pixel_art_with_provider_source`,零额外 GET;尚未取得原图的三条分支(进函数即预算耗尽、第一次回读失败、第一次回读超时)才走会回读的守卫,且该次 GET 以**外层请求 deadline**(而非已耗尽的像素预算)为绝对上界——用像素预算绑会让修复必然失败,不绑则突破预算。`apply_editor_postprocessed_alpha_from_persisted_provider_source_or_original` 因此新增可选 `download_deadline`,非像素路径传 `None` 保持既有语义不变。计数断言固定「回读守卫 3 处、内存守卫 4 处」,防止后续新增分支时误用回读版本。
|
||||
- 补充(同日):守卫的回读必须分两类处理。已取得 provider 原图的四条降级分支(permit 获取失败、worker 内 deadline、join 异常、worker 超时)改走纯内存守卫 `degrade_editor_pixel_art_with_provider_source`,零额外 GET;尚未取得原图的三条分支(进函数即预算耗尽、第一次回读失败、第一次回读超时)才走会回读的守卫。计数断言固定「回读守卫 3 处、内存守卫 4 处」,防止后续新增分支时误用回读版本。
|
||||
- OSS 回读口径(修正此前「最多增加一次 OSS GET」的措辞):约束是**不重复读取已经成功取得的对象**,而不是"整个请求至多一次 GET"。仅在尺寸漂移且尚未持有原图时才发起最多一次修复性回读,失败后不再重试;因此第一次回读失败或被像素预算掐断时,允许存在第二次、也是最后一次尝试——第一次超时往往并非 OSS 异常,而是被 30 秒像素预算切断,此时对象通常可正常读取,放弃修复反而会让角色更频繁地退化为原图单产物。
|
||||
- 回读上界:修复性回读必须始终有绝对 deadline。优先取外层 `request_deadline`,但它只在队列 worker 路径上有值——inline HTTP 请求的 `RequestContext` 默认 `external_call_deadline = None`,此时守卫自行以 `Instant::now() + EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION` 重新计时派生上界,不得退化为无界 `download.await`。`apply_editor_postprocessed_alpha_from_persisted_provider_source_or_original` 的可选 `download_deadline` 只对像素守卫传值,非像素路径继续传 `None` 保持既有语义不变。结构断言固定守卫内必须同时出现 `request_deadline.unwrap_or_else(` 与 `EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION`,防止兜底上界被移除后静默退回无界。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3263,8 +3263,16 @@ async fn degrade_editor_pixel_art_to_postprocessed_with_dimension_guard(
|
||||
reason: String,
|
||||
) -> (DownloadedOpenAiImage, Option<AppError>, Option<String>) {
|
||||
// 中文注释:只有尚未成功取得 provider 原图的降级分支才会走到这里。像素预算此时
|
||||
// 多半已经耗尽,不能拿它去绑这次回读(否则必然失败、守卫形同虚设),改用外层
|
||||
// 请求 deadline 作为绝对上界,保证这唯一一次 GET 有界。
|
||||
// 多半已经耗尽,不能拿它去绑这次回读(否则必然失败、守卫形同虚设)。优先用外层
|
||||
// 请求 deadline,但它只在队列 worker 路径上有值——inline HTTP 请求的
|
||||
// RequestContext 默认没有 external_call_deadline,此时必须自行重新计时派生一个
|
||||
// 上界,绝不允许出现无界 GET。
|
||||
let repair_deadline = request_deadline.unwrap_or_else(|| {
|
||||
let started_at = Instant::now();
|
||||
started_at
|
||||
.checked_add(EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION)
|
||||
.unwrap_or(started_at)
|
||||
});
|
||||
let (image, dimension_error) =
|
||||
apply_editor_postprocessed_alpha_from_persisted_provider_source_or_original(
|
||||
state,
|
||||
@@ -3272,7 +3280,7 @@ async fn degrade_editor_pixel_art_to_postprocessed_with_dimension_guard(
|
||||
delivery_width,
|
||||
delivery_height,
|
||||
postprocessed,
|
||||
request_deadline,
|
||||
Some(repair_deadline),
|
||||
)
|
||||
.await;
|
||||
(image, dimension_error, Some(reason))
|
||||
@@ -9423,12 +9431,19 @@ mod tests {
|
||||
"async fn apply_editor_postprocessed_alpha_and_pixel_art_from_persisted_provider_source_or_original",
|
||||
&["download_editor_persisted_image_object"],
|
||||
);
|
||||
// 会回读原图的守卫必须带绝对 deadline 参数,不允许无界 GET。
|
||||
// 会回读原图的守卫必须带绝对 deadline,且在外层 request_deadline 缺失时
|
||||
// (inline HTTP 请求的 RequestContext 默认就没有)必须自行派生兜底上界,
|
||||
// 不允许退化成无界 GET。
|
||||
assert_function_contains_in_order(
|
||||
source,
|
||||
"async fn degrade_editor_pixel_art_to_postprocessed_with_dimension_guard",
|
||||
"fn degrade_editor_pixel_art_with_provider_source",
|
||||
&["request_deadline: Option<Instant>", "request_deadline,"],
|
||||
&[
|
||||
"request_deadline: Option<Instant>",
|
||||
"request_deadline.unwrap_or_else(",
|
||||
"EDITOR_PIXEL_ART_MAX_PROCESSING_DURATION",
|
||||
"Some(repair_deadline),",
|
||||
],
|
||||
);
|
||||
// 守卫必须复用非像素路径的同一套尺寸比对与 alpha 回贴,保证尺寸一致时
|
||||
// 不产生额外 OSS GET,漂移修不好时返回尺寸错误。
|
||||
|
||||
Reference in New Issue
Block a user