You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4.3 KiB

status
accepted

跨模块批量编排执行器:BatchRunner(收拢两份同构 runBatch 的统一协议)

Context

ADR-0023 定下批量操作范式(非原子、逐条委派 self 代理、部分成功、BatchResult 骨架 + 各域自持失败项),但「逐条委派 + 失败翻译收集 + 结果组装」的编排皮留下两份同构实现:

  1. crm-lead LeadServiceImpl.runBatch(私有 19 行,8 个批量方法一行委派它)。
  2. crm-rule LeadPoolServiceImpl.deletePoolBatch(同一 try-catch 结构内联展开 19 行,差异仅失败项类型与 log 文案)。

后果:改兜底行为 / catch 结构要人肉排查两个模块——P1-6 类缺陷(规则两处实现漂移)的诞生结构;ADR-0023 D5 预言「此模式作为后续任何模块批量接口的范式」,但没有执行器载体,后续域(商机)只能再抄第三份。

Considered Options

(grilling 2026-08-20,五问五钉)

  • 范围与落位:crm-base 泛型执行器 + 两侧接线(选中)/com.crm.lead.batch 只收 lead 侧(一个调用方 = 假 seam;crm-rule 因依赖方向收不进来,跨模块重复留着)/再加 lead 门面包(为收而收)。事实修正:Controller 侧无编排逻辑(纯透传);批量不直接调 CAS 守卫(守卫在单条方法与状态机内),收的是编排皮。
  • interface 形态:静态 final 工具类 run(ids, op, bizFail, unknownFail) 四参数(选中——两个 ServiceImpl 构造器零变化、现有测试模式原样保留)/@Component bean(零依赖无状态,interface 是假 seam;两侧构造器各 +1 参数、测试构造全要动)/BatchAction record(op 每调用点必变,打包零复利)。
  • 测试分工:两侧现有测试一行不动(静态执行器真实穿过,自动升级为端到端锁)+ 新建 BatchRunnerTest 锁泛型协议(选中)/删两侧编排用例只留 BatchRunnerTest(被测对象没换家——删的是映射真值 + 端到端锁,净亏)。不套用候选 ② P1-6 平移先例。
  • 命名落位BatchRunner @ com.crm.base.domain.result(与 BatchResult 同包的协议家族,选中)/utils 包(成员皆无协议语义的通用工具,BatchRunner 吃 BusinessErrorExceptionBatchResult,是协议件不是工具件)。
  • 交付切分:单步一票(选中——改动面小于 LeadDeadlines 先例;建了不接线 = dead code 入库,无有意义的中间态)。

Decision

crm-base domain.result.BatchRunner:静态 run(ids, op, bizFail, unknownFail)——空判短路 → 逐条委派 → 业务异常经 bizFail(id, e) 翻译收集 → 未知异常 log + unknownFail(id, e) 兜底且不中断后续 → 组装 BatchResult<F>

  • 翻译工厂落各域失败项类LeadBatchFailItem.bizOf/unknownOf(兜底文案「操作失败」)、PoolBatchFailItem.bizOf/unknownOf(「删除失败」)——code→reason 映射与兜底文案由域自持,ADR-0023 D5 原样成立。
  • 失败项类型 F 经函数参数注入,BatchRunner 无业务枚举依赖——ADR-0023 D2「crm-base 非业务纯净」原样成立。
  • self-injection 留守两侧 service(AOP 每条独立事务,ADR-0023 D1 原样成立)。
  • 8 个 lead 批量方法与 deletePoolBatch 全部一行委派;runBatch 私有方法与内联编排删除(replace 不 layer)。

Consequences

  • 编排协议唯一家:改兜底行为 / catch 结构只动 crm-base 一处;商机等后续域批量接口直接复用,第三份实现不会诞生。
  • 两个 ServiceImpl 构造器零变化(静态方法不注入)——LeadBatchServiceTest(7)/ LeadPoolBatchDeleteTest(4)/ LeadPoolServiceImplTest P0-1 一行不动,自动升级为「委派 + 真实执行器 + 域翻译工厂」的端到端锁。
  • crm-base 测试 33 → 38 用例(+BatchRunnerTest 5:空判短路、全成功依序、bizFail 喂 (id, e)、unknownFail 兜底不中断、混合计数);crm-lead 116、crm-rule 30 不变。
  • 唯一行为微调:执行器内 log 统一为「批量操作单条异常:id={}」(原 leadId= / poolId= 域内文案消失;log 非 HTTP 契约)。
  • 决策来源:/improve-codebase-architecture 第三轮审查(2026-08-20,候选 ③)+ grilling 五问;实现票据见 .scratch/batch-runner-module/spec.md