--- name: 修复海康请求ID重复 overview: 确认根因是多实例部署下 `SnowflakeIdGenerator` 固定 `workerId=1, datacenterId=1`,同毫秒生成相同雪花 ID,导致并发海康请求的 `X-LR-REQUEST-ID` 重复。计划将海康 HTTP 请求 ID 改为 UUID 生成,避免跨实例碰撞。 todos: - id: fix-request-id content: MachineIntegrationAutoConfiguration:X-LR-REQUEST-ID 改为 ASRS + UUID(去掉 SnowflakeIdGenerator) status: pending - id: compile-verify content: 编译 baoshi-robot-integration 并并发验证请求 ID 唯一性 status: pending isProject: false --- # 修复海康 X-LR-REQUEST-ID 多实例重复 ## 问题确认 两条并发海康 `task/submit` 请求日志: - 不同 traceId:`5190815295754e028131f7bc18502911` / `5bf388d7211f4001bf7248d417240543` - 不同任务号:`MC2072288711575474302` / `MC2072288711575474213` - 不同线程:`robot-async-12` / `robot-async-16` - **相同** `X-LR-REQUEST-ID`:`ASRS2072313718577958912` 当前生成逻辑在 [`MachineIntegrationAutoConfiguration.java`](baoshi-robot/baoshi-robot-integration/src/main/java/com/baoshi/robot/machine/integration/autoconfigure/MachineIntegrationAutoConfiguration.java): ```java String requestId = "ASRS" + SnowflakeIdGenerator.generate(); ``` [`SnowflakeIdGenerator`](baoshi-common/common/src/main/java/com/baoshi/common/util/SnowflakeIdGenerator.java) 写死 `IdUtil.getSnowflake(1, 1)`。单 JVM 内 `nextId()` 是 synchronized 的,不会重复;**多实例同 workerId/datacenterId 时,同毫秒会产出相同 ID**。 ```mermaid sequenceDiagram participant PodA as PodA_robot_async_12 participant PodB as PodB_robot_async_16 participant HK as Hikvision_RCS PodA->>PodA: Snowflake(1,1) -> 2072313718577958912 PodB->>PodB: Snowflake(1,1) -> 2072313718577958912 PodA->>HK: X-LR-REQUEST-ID=ASRS2072313718577958912 PodB->>HK: X-LR-REQUEST-ID=ASRS2072313718577958912 ``` ## 修复方案(推荐) **海康 HTTP 请求 ID 改用 UUID**,与项目内同类场景保持一致: - [`WebClientUtil`](baoshi-wms/src/main/java/com/baoshi/wms/util/WebClientUtil.java) 对 `X-LR-REQUEST-ID` 已用 `UUID.randomUUID().toString().replace("-", "")` - 旧版 [`HikServiceClient`](baoshi-robot/baoshi-robot-hik/src/main/java/com/baoshi/robot/hik/client/HikServiceClient.java) 用 `RobotCodeGenerator`,跨实例仍有同毫秒碰撞风险 **变更点(1 个文件,约 2 行)** 修改 [`MachineIntegrationAutoConfiguration.java`](baoshi-robot/baoshi-robot-integration/src/main/java/com/baoshi/robot/machine/integration/autoconfigure/MachineIntegrationAutoConfiguration.java): ```java // 替换 String requestId = "ASRS" + SnowflakeIdGenerator.generate(); // 为 String requestId = "ASRS" + UUID.randomUUID().toString().replace("-", ""); ``` - 移除 `SnowflakeIdGenerator` import,增加 `java.util.UUID` import - 日志与 `.header(requestIdHeader, requestId)` 逻辑不变 - 重试分支(`doCall` 递归)每次仍会生成新 UUID,行为合理 **为何不用给 Snowflake 配 workerId** - `X-LR-REQUEST-ID` 只是外部请求幂等/追踪头,不需要时间有序 - UUID 零配置、跨实例天然唯一,改动最小 - 配置 workerId 需要 K8s/部署侧配合,且 [`CreateCodeUtil.machineTaskChainCode()`](baoshi-common-dao/src/main/java/com/baoshi/common/base/util/CreateCodeUtil.java) 也共用同一 `SnowflakeIdGenerator`,若要彻底修复 MC 号碰撞需另做专项 ## 验证 1. 编译 `baoshi-robot-integration` 模块 2. 本地或测试环境并发触发 2+ 个海康 `createTask`,确认日志中 `X-LR-REQUEST-ID` 均不同 3. 多 Pod 部署下复测(重点场景) ## 后续风险(本次不改动) `MC` 任务链号同样使用 `SnowflakeIdGenerator.generate()`,多实例极端并发下理论上也可能重复。若线上曾出现 MC 号冲突,建议单独立项:按实例配置 workerId 或改为 Redis 递增号段。