elevator(P1): bounded parallel delete, listFloor page, bind; Feign callWithContext

Made-with: Cursor
This commit is contained in:
反编译工作区
2026-04-25 08:29:53 +08:00
parent 7bcb72dc53
commit fe571aaadc
6 changed files with 321 additions and 49 deletions
@@ -11,9 +11,9 @@
| 约定 § | 代码锚点 | 子任务数(上界) | 下一可修正动作(建议顺序) | 不可修正或须前置确认 |
|--------|----------|------------------|----------------------------|------------------------|
| **§3.1** | `ImageRuleRefServiceImpl#delete`(约 575598 行) | **`N = param.getIds().size()`** 次 `updateGroupPersonRef`(每规则删后各 1 次) | **P0**:全部 `deleteById` 完成后,对本轮涉及的 `labelIds``organizationIds` **去重并集**,调用 **1 次** `updateGroupPersonRef`;为每次 RPC 增加 **`isSuccess` 校验**(与 §2.2 一致) | **须图库/通行确认**:合并调用是否为「刷新引用」语义、是否等价于当前 N 次效果;若不能确认则**不得合并**,仅可补返回值校验与日志(**工作区走查与方案审核见 §6**) |
| **§3.2** | `AcsPersonServiceImpl#delete`(约 165175 行) | **`P = param.getPersonIds().size()`** 次 `imageStorePersonService.delete` | **P1****有界并行**(并发度 48)调用 `delete`,失败聚合与现网「遇错即停」一致;已具备 `isSuccess` 分支,保持语义 | **无批量 delete**:无法改为单次 RPC,除非将来扩展契约(约定 §4 远期) |
| **§3.3** | `AcsPassRuleServiceImpl#listFloor` | **`F = passRuleResults.size()`** 次 `acsPersonService.page`(仅取 `totalRows` | **首轮已完成**`page.isSuccess()``getData()` 空防护、`rowsOfPage=1`。**P1 后续**:按楼层 **有界并行** `page`(保持结果顺序) | **禁止**本地 `countPersonIdByZoneId` 等替代 `page.totalRows`**无多 zone 一次统计 API** 时无法单 RPC 消除 N |
| **§3.4** | `AcsPassRuleServiceImpl#addImageStore`(约 195201 行) | **`D = deviceList.size()`** 次 `bindDeviceAndImageStore` | **P1****有界并行** `bind`并行失败时与现有 **回滚删图库** 逻辑一致(注意竞态与顺序) | **无批量 bind**:不能合并为 1 次 RPC(契约不扩展时) |
| **§3.2** | `AcsPersonServiceImpl#delete` | **`P = param.getPersonIds().size()`** 次 `imageStorePersonService.delete` | **P1 首轮已实施****§8**):`elevatorRemoteBoundedExecutor` 按批 `invokeAll`(默认并发 **6**),子线程 **`FeignThreadLocalUtil.callWithContext`**;遇失败**整批后**即返回 `CloudwalkResult.fail`(与原先顺序循环遇错即停一致,**非**单条失败即取消同批其它在途 RPC) | **无批量 delete**;同批内并行语义见 **§8.1** |
| **§3.3** | `AcsPassRuleServiceImpl#listFloor` | **`F = passRuleResults.size()`** 次 `acsPersonService.page` | **P1 首轮已实施****§8**):楼层 `page` 有界并行(默认 **6**),`personTotals[]` 按下标写回,**列表顺序不变** | **禁止**本地 count 替代 `totalRows`RPC 上界仍为 **F** |
| **§3.4** | `AcsPassRuleServiceImpl#addImageStore` 内设备绑图库 | **`D = deviceList.size()`** 次 `bindDeviceAndImageStore` | **P1 首轮已实施****§8**):`bind` 有界并行失败**`rollbackImageStoreAfterBindFailure`** 后抛 `ServiceException`(与同批已绑设备竞态与顺序循环**同类**) | **无批量 bind** |
| **§3.5** | `AcsDeviceTaskServiceImpl#updateFloors`(约 46119 行) | 增:**`A = addFloors.size()`** 次 `personRuleService.add``imageRuleRefService.addOnlyRule`;删:**`D = delFloorIds.size()`** 次 `personRuleService.delete` / `imageRuleRefService.delete` / DAO | **P1**:删层在 §3.1 落地后可减少「内层 refresh」放大;可对**楼层维度**做有界并行(与限流/异步线程池策略一致) | **`@Async("updateFloorsExecutor")`** 下线程池与背压须单独评估;错误现为 `throw new ServiceException(e.getMessage())` 信息较粗,是否属「接口不变」范畴由产品/运维定义 |
---
@@ -47,16 +47,20 @@
| **约定锚点** | **§3.5** `AcsDeviceTaskServiceImpl#updateFloors` |
| **暂缓项** | 楼层有界并行、`AbortPolicy``catch` 语义、删楼 `ruleMap` 缺键等见 **§7.3**。 |
### 迭代 4 及以后(P1 工程批次
### 迭代 4**P1:§3.2 / §3.3 / §3.4 + 统一有界池**
在迭代 3 首轮修正稳定后,按 ROI 与风险分批推进(均需单独走查闸门):
| 字段 | 内容 |
|------|------|
| **状态** | **已实施**(实现说明与语义边界见 **§8**)。 |
| **线程池 Bean** | `elevatorRemoteBoundedExecutor``ElevatorRemoteIoExecutorConfig`),配置前缀 **`ninca.elevator.remote-io.pool`**(默认 core=max=**6**queue=512`CallerRunsPolicy`)。**未**与 `updateFloorsExecutor` 合并,避免异步任务与同步 RPC 抢同池。 |
| **公共能力** | `FeignThreadLocalUtil.callWithContext``cw-elevator-application-common`):子线程执行 Feign 前绑定/恢复 ThreadLocal 请求头。 |
1. **§3.2**`AcsPersonServiceImpl#delete` — 有界并行 `imageStorePersonService.delete`,失败策略与现网一致。
2. **§3.3**`AcsPassRuleServiceImpl#listFloor` — 有界并行 `acsPersonService.page`**保持楼层顺序**合并结果。
3. **§3.4**`AcsPassRuleServiceImpl#addImageStore` — 有界并行 `bindDeviceAndImageStore`,失败与**回滚删图库**与现逻辑一致。
4. **统一线程池**:迭代 3 若已梳理 `updateFloorsExecutor`,再决定 P1 是否复用命名池或独立有界池,并在 PR 中写明并发度、超时与遇错策略。
### 迭代 5 及以后(可选深化)
**已完成回顾**:迭代 1 — `listFloor` 首轮修正(**§5**);迭代 2 — §3.1 仅文档走查(**§6**),代码冻结见上表。
- **§3.5**`updateFloors` 内楼层循环有界并行(仍受 §3.1 内层放大约束)。
- **调参 / 观测**`ninca.elevator.remote-io.pool` 按环境压测调整;必要时为并行批增加指标日志。
**已完成回顾**:迭代 1 — **§5**;迭代 2 — **§6**(§3.1 冻结);迭代 3 — **§7**;迭代 4 — **§8**。
---
@@ -170,3 +174,21 @@
- **暂缓(须单独评审)**:按楼层 **有界并行**、拒绝策略、`catch` 异常语义增强、`ruleMap` 缺键防护。
**修正实施后**:提交 **`0ddeedc`**(分支 `v0.11`)。
---
## 8. 迭代 4P1 有界并行(§3.2 / §3.3 / §3.4
**实施日期**2026-04-25
### 8.1 行为与约定对齐说明
| 项 | 说明 |
|----|------|
| **并发度** | 代码常量与默认池 **`corePoolSize=maxPoolSize=6`**(约定 48 区间内),可通过 **`ninca.elevator.remote-io.pool.core-pool-size` / `max-pool-size`** 覆盖。 |
| **§3.2 `delete`** | 多 `personId` 时按批 `ThreadPoolExecutor.invokeAll`;单 ID 仍走主线程(无 Feign 子线程问题)。失败时返回 **`76260407`** 风格 `CloudwalkResult.fail`,与改造前**一致**;**同批内**若某 RPC 失败,`invokeAll` 仍会等本批其它任务结束后再统一 `get()` 抛出/返回,与**严格单线程「第一条失败即不再发起后续」**在「已发起请求数」上略有差异,属典型有界并行取舍。 |
| **§3.3 `listFloor`** | 设备数仍顺序 DAO`acsPersonService.page` 按批并行,结果写入 `personTotals[idx]` 后顺序 `setPersonNumber`**响应楼层顺序不变**。 |
| **§3.4 `addImageStore`** | `bindAppImageStoreDevice` 仍顺序执行;仅 **`bindDeviceAndImageStore`** 按批并行;任一批次中失败则 **`rollbackImageStoreAfterBindFailure`**(抽方法)后抛 `ServiceException`,与原先 try/catch 回滚路径一致。 |
| **Feign ThreadLocal** | 所有子线程 RPC 经 **`FeignThreadLocalUtil.callWithContext`**,避免池化线程串请求头。 |
**实施后提交****`7eb3785`**(分支 `v0.11`)。