From ec23c0d77c3e36689d31b359f0aaf3b2261d5ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Fri, 4 Sep 2026 23:07:58 +0800 Subject: [PATCH] =?UTF-8?q?task-170:=20=E7=B4=AB=E9=B8=9F=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E9=85=8D=E7=BD=AE=E6=8E=A5=E5=85=A5=EF=BC=88?= =?UTF-8?q?ZiniaoHttpConfigResolver=20=E8=B6=85=E6=97=B6/=E9=87=8D?= =?UTF-8?q?=E8=AF=95=E8=AF=BB=E5=8F=96=EF=BC=8Cread=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=BA=A7=E7=8E=B0=E6=9C=89=E9=85=8D=E7=BD=AE=E4=BC=98=E5=85=88?= =?UTF-8?q?=E3=80=81=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=E5=85=9C=E5=BA=95?= =?UTF-8?q?=EF=BC=89+=208=20=E6=9D=A1=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resolver 提供 connect/read/call/maxRetries/baseRetryDelay 访问面,不改动 ZiniaoClientImpl 调用点 - read 优先取 aiimage.ziniao.read-timeout-seconds(生产默认 15s,与 requestFactory(15000) 现状一致),未配置回退 aiimage.http-client.* - 仅新增类与测试,零生产行为变化 --- .../config/ZiniaoHttpConfigResolver.java | 50 ++++++++++ .../config/ZiniaoHttpConfigResolverTest.java | 96 +++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 backend-java/src/main/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolver.java create mode 100644 backend-java/src/test/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolverTest.java diff --git a/backend-java/src/main/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolver.java b/backend-java/src/main/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolver.java new file mode 100644 index 00000000..11131327 --- /dev/null +++ b/backend-java/src/main/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolver.java @@ -0,0 +1,50 @@ +package com.nanri.aiimage.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 紫鸟客户端统一配置解析(task-170)。 + * + * 真实基线(已核实):连接超时来自共享 HttpClient(HttpClientPool connect=10s, + * 不读 aiimage.ziniao.connect 字段);读取超时由 ZiniaoClientImpl 取 + * aiimage.ziniao.read-timeout-seconds*1000(生产默认 15s)经 requestFactory 生效; + * 当前无 call timeout / 无重试。 + * + * 语义:read 优先取模块级现有配置(保证接入切点时行为不变),未配置时回退命名空间 + * aiimage.http-client.*;connect/call/retry 取命名空间(未来由命名空间统一治理)。 + * 仅提供稳定访问面,不改动 ZiniaoClientImpl 调用点。 + */ +@Component +@RequiredArgsConstructor +public class ZiniaoHttpConfigResolver { + + private final HttpClientProperties httpClientProperties; + private final ZiniaoProperties ziniaoProperties; + + /** 连接超时:共享 HttpClient 决定,命名空间默认 10s 与 HttpClientPool 现状一致。 */ + public long connectTimeoutMillis() { + return httpClientProperties.effectiveConnectTimeoutMillis(); + } + + /** 读取超时:模块级秒数优先(现状 15s);未配置时回退命名空间。 */ + public long readTimeoutMillis() { + int moduleSeconds = ziniaoProperties.getReadTimeoutSeconds(); + if (moduleSeconds > 0) { + return moduleSeconds * 1_000L; + } + return httpClientProperties.effectiveReadTimeoutMillis(); + } + + public long callTimeoutMillis() { + return httpClientProperties.effectiveCallTimeoutMillis(); + } + + public int maxRetries() { + return httpClientProperties.effectiveMaxRetries(); + } + + public long baseRetryDelayMillis() { + return httpClientProperties.getBaseRetryDelayMillis(); + } +} diff --git a/backend-java/src/test/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolverTest.java b/backend-java/src/test/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolverTest.java new file mode 100644 index 00000000..adafefee --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/config/ZiniaoHttpConfigResolverTest.java @@ -0,0 +1,96 @@ +package com.nanri.aiimage.config; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * task-170:紫鸟客户端配置接入契约(plan 10,诚实模式)。 + * + * 现网真实基线(已核实): + * - 连接超时:共用 HttpClient(HttpClientPool connect=10s),不读 aiimage.ziniao.connect 字段; + * - 读取超时:ZiniaoClientImpl 用 ziniaoProperties.readTimeoutSeconds*1000(生产默认 15s); + * - 无 call timeout / 无重试。 + * + * resolver 语义:模块级现有配置优先(read 取 aiimage.ziniao 秒数),命名空间兜底; + * 不改调用点,保证接入未来切点时行为不变。 + */ +class ZiniaoHttpConfigResolverTest { + + private HttpClientProperties http; + private ZiniaoProperties ziniao; + private ZiniaoHttpConfigResolver resolver; + + @BeforeEach + void setUp() { + http = new HttpClientProperties(); + ziniao = new ZiniaoProperties(); + resolver = new ZiniaoHttpConfigResolver(http, ziniao); + } + + @Test + void readDefaultsToCurrentZiniaoModuleConfig() { + // 生产现状:aiimage.ziniao.read-timeout-seconds=15 → requestFactory(15000) + ziniao.setReadTimeoutSeconds(15); + assertEquals(15_000L, resolver.readTimeoutMillis()); + } + + @Test + void moduleReadWinsOverNamespace() { + // 模块级现有配置优先,命名空间覆盖不影响紫鸟 read(行为不变) + ziniao.setReadTimeoutSeconds(15); + http.setReadTimeoutMillis(120_000); + assertEquals(15_000L, resolver.readTimeoutMillis()); + } + + @Test + void readFallsBackToNamespaceWhenModuleUnset() { + // 模块未配置(<=0) → 命名空间 read(默认 60s,可覆盖) + ziniao.setReadTimeoutSeconds(0); + assertEquals(60_000L, resolver.readTimeoutMillis()); + http.setReadTimeoutMillis(30_000); + assertEquals(30_000L, resolver.readTimeoutMillis()); + } + + @Test + void connectMatchesSharedClientBaseline() { + // 连接超时由共享 HttpClient 决定(HttpClientPool 硬编码 10s),不读模块 connect 字段 + assertEquals(10_000L, resolver.connectTimeoutMillis()); + http.setConnectTimeoutMillis(30_000); + assertEquals(30_000L, resolver.connectTimeoutMillis()); + } + + @Test + void callTimeoutFromNamespace() { + assertEquals(90_000L, resolver.callTimeoutMillis()); + http.setCallTimeoutMillis(180_000); + assertEquals(180_000L, resolver.callTimeoutMillis()); + } + + @Test + void retryFromNamespaceClamped() { + assertEquals(3, resolver.maxRetries()); + http.setMaxRetries(99); + assertEquals(10, resolver.maxRetries(), "命名空间重试钳制到 10"); + assertEquals(500L, resolver.baseRetryDelayMillis()); + } + + @Test + void invalidNamespaceTimeoutsClamped() { + http.setConnectTimeoutMillis(-1); + assertEquals(1_000L, resolver.connectTimeoutMillis()); + ziniao.setReadTimeoutSeconds(0); + http.setReadTimeoutMillis(999_999_999L); + assertEquals(3_600_000L, resolver.readTimeoutMillis(), "命名空间 read 钳制到 3600s"); + } + + @Test + void resolverWiredAsStableAccessSurface() { + // 作为未来 ZiniaoClientImpl 切换读取源时的稳定访问面 + assertTrue(resolver.connectTimeoutMillis() > 0); + assertTrue(resolver.readTimeoutMillis() > 0); + assertTrue(resolver.maxRetries() >= 0); + } +}