48 KiB
msgexchange-api 旧项目业务逻辑与用户故事文档
0. 文档说明
nextgen 定位注(msgexchange-v2):本文件描述 legacy 行为基线。nextgen 为上游报文 处理中间件——生产主路径 = JDBC 轮询共享 MySQL
CMINMSGS(上游经 CIIMS 等外部落信); legacy §3.1 HTTP 收报与 §3.2 轮询在现役并存,nextgen 将轮询提升为主拓扑、HTTP 降为 compat (见仓库docs/architecture.md)。
- 本文档记录 msgexchange-api(现役旧项目)的完整业务逻辑,并以用户故事形式组织,作为新系统(Micronaut + Kotlin)迁移设计及一致性对拍的行为基线。
- 内容依据仓库源码与资源配置编写:
src/main/java/com/gzzn/omms/msgexchange-api/**、src/main/resources/*.yml;分支feature/add_dev_containers_supports(HEADeb72a668)。 - 报文结构依据
SIS_AODB_RMS-V0.1.md与unisysaodbsis.xsd(同目录 docs/legacy/)。 - 优先级:本文只描述现役行为;与
SIS_AODB_RMS-V0.1.md冲突时以 SIS 为准。 - 文档中"关联代码"均为相对仓库根目录的源码路径,可据此逐条复核。
1. 系统定位与集成边界
msgexchange-api 为成都机场 OMMS 消息交换服务(com.gzzn.omms:msgexchange-api,1.2.1-SNAPSHOT;Spring Boot 1.5.17 / Spring Cloud Edgware / Java 8;服务名 msgexchangeapi)。端口 8080 为 Spring Boot 缺省值——各 application-*.yml 均未配置 server.port,迁移时勿寻找该配置项。
职责概述:
- 接收上游系统(AODB / CIIMS 等)下发的航班计划与动态 XML 报文;
- 将报文落库(
CMINMSGS)后异步解析处理,维护"最新动态航班库"(Redis); - 通过 Kafka 将航班变更通知前端(ACDW);
- 将已结束运营的航班沉淀为历史数据(Elasticsearch、MySQL 历史表);
- 提供 HTTP 接口用于收报、日计划请求、动态航班查询与运维操作。
外部集成点如下:
| 集成对象 | 用途 | 说明 |
|---|---|---|
MySQL(库 cdairport) |
消息持久化 | 表 CMINMSGS(入站报文)、CMINMSGS_HST(历史)、CMINMSGS_TEST(测试)、COUTMSGS(出站报文) |
| Redis Cluster | 动态航班库、基础数据缓存 | key flightInfo、orms_stand、orms_stand_airbridge;RedisTemplate 启用 Jackson enableDefaultTyping |
| Kafka | 通知前端 | 业务主题 msg(单条事件)、schd(定时批量);另提供任意主题转发接口;本服务仅生产、不消费(无 @KafkaListener) |
| Elasticsearch 6.x | 历史航班存储 | transport 客户端(9300);索引 flight_hts、flight_hts2;dev 配置 cluster.name=opensearch |
| Eureka | 服务注册、admin-api 服务发现 | @LoadBalanced RestTemplate 按服务名 ADMINAPI 调用 |
| admin-api(ACAA) | 基础数据 | 机位列表、机位→登机桥编码两个接口(basicdata 模块) |
| Logstash(logback) | 日志采集 | TCP socket 输出 JSON 日志 |
参与角色:报文发送方(上游系统或手工工具)、前端使用者(ACDW)、计划/签派操作员、值班运维人员、系统自身(轮询线程与定时任务)。
2. 术语与数据语义
| 术语 | 定义 |
|---|---|
CMINMSGS 记录 |
一条入站原始报文。列:CMINMSGS_ID(自增主键)、CMINMSGS_CLOB_MSG(原始 XML)、CMINMSGS_DATE_RECEIVED(接收时间)、CMINMSGS_DATE_PROCESSED、CMINMSGS_STATUS、CMINMSGS_SUBSYSTEM_*(子系统信息;现役处理时未回填) |
| 处理标记语义 | 收报时 CMINMSGS_DATE_PROCESSED=NULL;处理完成(含失败或命中忽略清单)后由 Handler 置为当前时间。Handler 返回失败且未置位时(如日计划刷新失败、ADFT 数量校验失败),后续轮询将再次处理该消息 |
MSG |
报文根对象(entity/msg/MSG.java):META(TYPE / STYP / SNDR / DTTM / SEQN)与业务体(SCHD / FLOP / RQFD 等) |
SCHD.FLTR |
动态航班对象,存储于 Redis flightInfo。关键字段:FLID(航班标识)、SODT/ACTT/CNCL(计划/实际/取消时间,格式 ddMMMyyHHmm)、MVIN(A=到港,D=离港)、MAID(共享航班主航班 FLID)、MAFL(主航班的共享航班列表)、ABTM 及派生字段 abdg、PSDT/LPSDT(当前/历史计划机位)、DELY/ABN(延误与异常) |
ABN 异常列表 |
类型:DLY(延误数组)、CAN(取消)、RTN(返航)、ALT(备降) |
| 共享航班 | MAID != NULL 的航班。其自身变更不直接发送 Kafka 消息,随主航班(MAID 指向的航班)变更一并下发 |
| Handler | 消息子类型的处理类,命名规则 msghandler/{type小写}/{STYP}Handler。Handler 非 Spring 管理的 Bean:由 Dispatcher 反射实例化,依赖经 SpringUtil 获取 |
ignoreMsg |
忽略规则,逗号分隔的 TYPE-STYP 或 TYPE-*。命中的消息不进入 Handler,直接标记为已处理 |
flightInfo |
Redis hash:field=FLID,value=SCHD.FLTR(带类型信息的 JSON 序列化) |
orms_stand |
Redis hash:field=机位编码,value=OrmsStand 对象 |
orms_stand_airbridge |
Redis hash:field=机位编码,value=登机桥编码数组的 JSON 字符串 |
COUTMSGS |
出站报文表,列清单见 5.5 |
3. 端到端业务流程
3.1 入站收报
POST /cminmsgs/send,请求体为原始 XML 字符串。
调用链:CminmsgsController.send → CminmsgServiceImpl.sendXmlMsg。处理内容:
- 创建
CMINMSGS记录:CLOB_MSG保存原始 XML,DATE_RECEIVED设为当前时间,DATE_PROCESSED为空; - 落库并返回自增 ID(
ResponseDto.success(id))。
收报接口不解析、不校验报文内容;业务处理异步进行。
3.2 消息采集与分派
- 启动:
AppRunner(CommandLineRunner)调用MsgExchangeServiceImpl.start(),以ScheduledExecutorService(单线程,命名msgexchange-%d)按msgExchange.intervalSeconds(各环境均配置为 1 秒,代码无默认值)固定频率执行MsgExchangeRunner。 - 采集:
MsgExchangeRunner.run调用cminmsgService.getNewMsgsAfterId(0L),即查询CMINMSGS_ID > 0 且 DATE_PROCESSED IS NULL的记录,逐条调用MsgHandlerDispatcher.dispatch;异常仅记录日志,不中断批次。 - 分派:
MsgHandlerDispatcher.dispatch执行以下步骤:exchangeService.xmlToMsg(clob)将 XML 解析为MSG(JacksonXmlMapper+ JAXB 注解 introspection),构造CminmsgWapper;- 读取
META.TYPE与META.STYP;若命中ignoreMsg,将该记录标记为已处理并返回成功; - 否则按命名规则反射加载 Handler(
Class.forName+newInstance),调用run(CminmsgWapper); - 任一步骤抛出异常:将该记录标记为已处理(避免滞留待处理队列)、记录错误日志、返回失败(不重试)。
3.3 计划类(SCHD-*)处理
分派目标为 msghandler/schd/*Handler(继承 SchdBaseHandler)。
RESP / DNLD(日航班计划刷新,实现相同)
RESPHandler.run / DNLDHandler.run 调用 FlightInfoServiceImpl.updateByDaySchd:
- 读取
SCHD.FLTR全量列表; updateMafltr:将共享航班(MAID != NULL)生成MAFLDATA(FLID, FLNO),追加到对应主航班的MAFL列表;updatefltrBridge:将各航班ABTM中的ABDG按序直接追加到派生字段abdg(代码不插入分隔符——分隔符依赖ABDG数据本身是否带逗号),拼接结果若以逗号结尾则仅删除末尾一个逗号;- 调用
redisService.hmset("flightInfo", FLID→FLTR)写入航班集合。
说明:RedisService.hmset 实现为 opsForHash().putAll,仅新增/覆盖 field;这是 legacy 行为记录,不构成新系统的设计依据。
刷新成功:调用 sendDschd 向 Kafka 主题 msg 发送日计划到达通知(MSG 仅保留 META,业务体为空),随后将该记录标记为已处理,返回成功。
刷新失败(updateByDaySchd 返回 false):不标记已处理,返回失败;该消息在后续轮询中重试。
ADFT(计划外航班添加)
ADFTHandler.run(实际执行顺序):
- 校验
SCHD.FLTR数量为 1,否则直接HandlerResult.failure()返回且不标记已处理(与 RESP/DNLD 刷新失败同属"返回失败未置位"分支,后续轮询重试,见 5.7-2); saveFltr将航班写入 Redis(hset);- 非共享航班(
MAID == NULL):加入发送缓冲并调用sendMsg发送完整消息 JSON 至 Kafkamsg; - 标记已处理(此步先于下方共享航班联动执行,代码中非共享发送与标记先于共享联动,与"处理完再标记"的直觉不同);
- 共享航班(
MAID != NULL):不直接发送;从 Redis 取主航班(flightInfoService.getByFlid),向主航班内存对象MAFL追加MAFLDATA(FLID, FLNO),再将变更后的主航班加入发送缓冲——未调用saveFltr写回 Redis(与 FDEL 同类遗留缺陷,见 5.7-14);若主航班不存在(getByFlid返回 null),此处对 null 取getMafl()会抛空指针(Dispatcher 异常兜底会再次标记已处理)。
3.4 动态类(FLOP-*)处理
分派目标为 msghandler/flop/*Handler(共 29 个,继承 FlopBaseHandler)。通用处理流程 FlopBaseHandler.run:
- 取
FLOP.FLID,调用flightInfoService.getByFlid查询 Redis; - 航班不存在:标记已处理、记录告警、返回失败(视为处理完成,不再重试);
- 航班存在:
- 子类覆写的
updateFltr(FLOP, FLTR)就地更新动态航班(子类语义见 5.3); saveFltr写回 Redis;- 若为非共享航班(
MAID == NULL):加入发送缓冲并调用sendMsg发送至 Kafkamsg; - 标记已处理,返回
success(FLTR)。
- 子类覆写的
例外:FDELHandler 覆写 run(删除航班)。处理内容:
- 航班存在:
deleteFltr删除 Redis 记录;无条件调用sendMsg发送删除消息(由前端执行本地删除),不区分共享/非共享航班(与下述通用规则不一致,见 5.7);标记已处理; - 被删航班为共享航班:从主航班
MAFL中移除对应元素,并将变更后的主航班加入发送缓冲。该修改仅作用于从 Redis 读出的内存对象(未调用saveFltr写回 Redis),元素比对使用==(MAFLDATA.getFlid()与FLTR.getFLID()均为BigInteger,故为引用比较而非值比较),属遗留缺陷(见 5.7); - 航班不存在:标记已处理并返回失败。
共享航班联动规则(通用,FDEL 除外):动态与计划 Handler 对共享航班(MAID != NULL)自身变更不单独发送消息;主航班自身变更(更新、删除联动)将主航班放入发送缓冲,共享航班列表随主航班一并下发。
3.5 前端通知(Kafka)
- 即时事件(主题
msg):由 3.3、3.4 中sendMsg/sendDschd发送。exchangeService.msgToJson序列化META与 TYPE 对应的业务体。 - 批量缓冲(主题
schd):FltrSendScheduled(每 3 秒,cronscheduled.flightSendCron)调用FltrSendBufferServiceImpl.takeAllFltr取空进程内队列(ConcurrentLinkedQueue),经JsonUtil.getString序列化后发送至 Kafkaschd。队列为空时不发送。 - 现役为 at-most-once:
takeAllFltr在 Kafka 发送前即复制并清空队列;序列化或发送异常仅记录日志、不回灌队列,该批消息可能整体丢失(见 US-B2、5.7-17)。
3.6 入站报文历史归档
CminmsgsHisScheduled(cron 0 0 3 * * ?,即 scheduled.cminmsgHisCron)调用 CminmsgHstDao.moveToHistory,以原生 SQL 在单事务内执行:
INSERT INTO cminmsgs_hst SELECT ... FROM cminmsgs src WHERE NOT EXISTS(cminmsgs_hst 中已存在相同 ID)AND src.CMINMSGS_DATE_RECEIVED < NOW() - 1 DAY;DELETE FROM cminmsgs WHERE CMINMSGS_DATE_RECEIVED < NOW() - 1 DAY。
说明:CmoutmsgHstServiceImpl 与 insertToTable 中按 CMINMSGS_ID % 10 分表(cminmsgs_hst_0 至 cminmsgs_hst_9)的历史归档实现仍保留于代码中,但未被当前定时任务使用。
3.7 动态航班转历史
FlightHisScheduled(cron 0 30 3 * * ?,即 scheduled.flightInfoCron)执行以下步骤:
flightInfoService.findAll:读取 RedisflightInfo全部动态航班;FlightHisServiceImpl.getHisToBeTran:按下列任一条件判定可转历史(时间字段格式ddMMMyyHHmm,阈值为毫秒,见 5.4):SODT(计划时间)距当前时间超过SODT_HST_TIME(3 天);CNCL(取消时间)距当前时间超过CANCEL_HST_TIME(1 小时);- 备降:
FDIV.DDES = CTU且FDIV.DDIR = FROM(应降成都、实际备降他处),且SODT距当前时间超过FDIV_HST_TIME; - 离港(
MVIN = D):计划时间早于当日且存在实际时间ACTT,且ACTT不晚于当前时间; - 到港(
MVIN = A):计划时间早于当日且存在实际时间,且ACTT距当前时间超过ARRIVE_HST_TIME(1 小时);
FlightHisServiceImpl.save:逐条按SODT + FLID查询 ES 索引flight_hts(type_doc),存在则更新、不存在则新增;写入内容为JSONObject.parseObject(JsonUtil.getString(FLTR));单条失败记录日志并跳过;- 保存成功的
FLID列表经flightInfoService.batchDeleteFltr从 Redis 批量删除。
说明:getHisToBeTran(步骤 2)的逐条判定未做单条异常隔离:SODT 在四个判定方法中均无空值保护直接解析(缺失/非法即抛异常);ACTT/CNCL 为空有保护、仅"非空但格式非法"才抛;MVIN 为空且 ACTT 存在时 equals 调用(isDMatch:236、isAMatch:264)会 NPE。任一条抛异常都会由 FlightHisScheduled 外层捕获并中断当次整批,剩余航班不再处理;"单条失败不影响其他航班"仅适用于步骤 3 save 的 ES 写入循环(见 US-D2、5.7-18)。
3.8 HTTP 查询与运维接口
GET /all/flights:读取 Redis 全部动态航班,过滤掉共享航班(MAID != NULL)后返回ResponseDto<List<SCHD.FLTR>>。GET /flights/migrate:scroll 读取 ESflight_hts全量数据,经transToNewFltrs还原SCHD.FLTR(将ABN[].BODY按类型 DLY / CAN / RTN / ALT 映射回对象字段),逐条写入 ESflight_hts2。该接口为一次性数据迁移工具。POST /kafka/topics/{name}/msgs:请求体先按 JSON(Map)解析,成功则直接发送至 Kafka 主题{name};解析失败则按 XML 解析为MSG再转 JSON 发送。该接口提供 XML / JSON 双模转发能力。POST /schd/sync:见 3.9。
3.9 日计划请求(出站报文构造)
POST /schd/sync,请求体 SchdSyncDto {startDate, endDate},时间格式 yyyy-MM-dd hh:mm。
SchdController.sync 解析时间后调用 CmoutmsgServiceImpl.sendSchdGetMsg:
- 生成序号:
SEQN = max(COUTMSGS_ID) + 1;无记录时为1; - 构造报文:
META{SNDR=OSH5, TYPE=RQFD, STYP=NONE, DTTM=yyyyMMddHHmmss, SEQN},业务体RQFD{STDB, STDE}(时间格式ddMMMyyHHmm,大写);使用MSGBuilder与METABuilder; exchangeService.msgToXml序列化为 XML(根元素MSG,含xsi:noNamespaceSchemaLocation="unisysaodbsis.xsd");- 写入
COUTMSGS:CLOB_MSG为报文 XML,DATE_INSERTED为当前时间,ROUTINGID = OSH5RQFD。
代码检索结果:现役工程中不存在读取或发送 COUTMSGS 的执行器(对 CmoutmsgDao 的引用仅存在于 CmoutmsgServiceImpl 的 save 与 findMaxId)。/schd/sync 仅完成报文构造与落库,实际发送通道需另行确认。
3.10 基础数据(机位与登机桥)
OrmsStandManager(单例,非 Spring Bean):读取 Redisorms_stand;键不存在时经OrmsStandServiceImpl.findAll(RestTemplateGETadminApi.ormsStandsUrl,按 Eureka 服务名ADMINAPI解析)拉取全量机位,以standCode → OrmsStand写入 Redis(过期时间 3600 秒),随后读取返回。OrmsStandAirbridgeManager(单例,非 Spring Bean):读取 Redisorms_stand_airbridge;机位字段无缓存时经getAirbridgeCodeByStandCode(GET.../ormsStands/{standCode}/airbridgeCode)拉取,以 JSON 数组字符串存入 hash 字段,再读取并解析为List<String>。- 使用方:机位相关 Handler(如
PSDTHandler.updateAbg)。处理规则:取最后一个计划机位编码查询机位基础数据;机位类型standType = near(近机位)时将登机桥编码拼接至abdg;远机位或清空机位消息时置abdg为空。
4. 用户故事
用户故事格式:
ID | 角色 | 期望能力 | 业务目标。每条包含触发条件、处理流程(代码链路)与验收标准。 角色代号:上游 = 报文发送方;前端 = ACDW 使用者;计划 = 计划/签派操作员;运维 = 值班运维人员;系统 = 系统自身(轮询线程与定时任务)。
EPIC-A 入站消息生命周期
US-A1 接收并持久化上游 XML 报文
- 角色 / 期望 / 目标:作为上游,期望提交完整 XML 报文并即时取得受理标识,以便确认报文已受理待处理。
- 触发条件:
POST /cminmsgs/send,请求体为 XML 文本。 - 处理流程:
CminmsgsController.send→CminmsgServiceImpl.sendXmlMsg(CMINMSGS落库:CLOB_MSG保存原始报文、DATE_RECEIVED为当前时间、DATE_PROCESSED为空)→ 返回受理 ID。 - 验收标准:
- 响应结构
{is_success: true, body: <自增 ID>}; - 数据表新增一条记录,且
DATE_PROCESSED为空; - 报文原样保存,不做解析或校验。
- 响应结构
- 关联代码:
controller/CminmsgsController.java、service/CminmsgServiceImpl.java、dao/CminmsgDao.java、entity/Cminmsg.java。
US-A2 定期采集未处理报文并分派
- 角色 / 期望 / 目标:作为系统,期望周期性获取未处理报文并按类型转交对应 Handler,以便报文得到业务处理。
- 触发条件:应用启动后,按
msgExchange.intervalSeconds(各环境均配置为 1 秒,代码无默认值)周期执行。 - 处理流程:
MsgExchangeServiceImpl.start→MsgExchangeRunner.run(查询ID > 0 且 DATE_PROCESSED IS NULL)→MsgHandlerDispatcher.dispatch(解析 XML、反射调用 Handler)。 - 验收标准:
- 已处理(
DATE_PROCESSED非空)的记录不会被再次采集; - 单条消息处理异常不影响同批其他消息;
- 需区分"抛异常"与"Handler 返回失败":抛异常由 Dispatcher 兜底标记已处理(不会无限滞留);Handler 返回失败且未标记的分支(RESP/DNLD 刷新失败、ADFT 数量校验失败)会被轮询持续重试,直至每日归档移入历史表(见 5.7-2)。
- 已处理(
- 关联代码:
runner/AppRunner.java、runner/MsgExchangeRunner.java、service/MsgExchangeServiceImpl.java、msghandler/MsgHandlerDispatcher.java、service/exchange/ExchangeServiceImpl.java。
US-A3 忽略清单内消息仅登记不处理
- 角色 / 期望 / 目标:作为上游,期望指定类型消息(如
LDM-*、REGN-*、RSTA-*、EROR-*)跳过业务处理,以避免无效处理与噪声日志。 - 触发条件:报文的
META.TYPE-STYP命中msgExchange.ignoreMsg规则(逗号分隔,支持TYPE-STYP与TYPE-*,大小写不敏感)。 - 处理流程:
MsgHandlerDispatcher.isNeedHandler判定为不需要处理 →updateBatchProcessed标记已处理 → 返回成功。 - 验收标准:
- 命中规则的记录被标记为已处理;
- 不触发任何 Handler 反射调用。
- 关联代码:
msghandler/MsgHandlerDispatcher.java;配置项msgExchange.ignoreMsg于各环境application-*.yml(注意:test 环境值为error-*,其余环境为eror-*,属现存差异)。
US-A4 日航班计划快照整体刷新(SCHD-RESP / SCHD-DNLD)
- 角色 / 期望 / 目标:作为上游,期望下发某时段的日航班计划(含多航班
FLTR列表),以便本服务与前端获得最新计划基线。 - 触发条件:收到
SCHD-RESP或SCHD-DNLD报文。 - 处理流程:
RESPHandler.run/DNLDHandler.run→FlightInfoServiceImpl.updateByDaySchd:- 重组共享航班(
MAFLDATA挂入主航班MAFL); - 重组登机桥(
ABTM的ABDG按序直接追加为abdg,见 3.3); hmset("flightInfo", FLID→FLTR)合并写入(新增/覆盖 field,不删除快照中未出现的旧 field);- 成功后发送日计划到达通知至 Kafka
msg,并标记已处理。
- 重组共享航班(
- 验收标准:
- Redis
flightInfo合并写入:报文内航班被新增/覆盖;该行为仅供 legacy 对拍使用; - 主航班
MAFL包含各共享航班的FLID/FLNO; - 各航班
abdg为ABDG值按序直接追加的结果:分隔符依赖数据本身,代码不插入分隔符;仅当拼接结果以逗号结尾时删除末尾一个逗号。回放测试需按该真实机制设定期望(见 3.3); - Kafka
msg收到仅含META的通知消息; - 刷新失败时该消息不标记已处理,后续轮询重试。
- Redis
- 关联代码:
msghandler/schd/RESPHandler.java、msghandler/schd/DNLDHandler.java、service/flightInfo/FlightInfoServiceImpl.java、service/exchange/ExchangeServiceImpl.java、service/CminmsgServiceImpl.java。
US-A5 添加计划外临时航班(SCHD-ADFT)
- 角色 / 期望 / 目标:作为上游,期望推送单条临时航班计划,以便其进入动态航班库并即时通知前端。
- 触发条件:收到
SCHD-ADFT报文。 - 处理流程:
ADFTHandler.run(按代码实际顺序;约束:仅处理FLTR恰含 1 条的报文,数量≠1 属失败路径而非超出处理范围):- 校验
FLTR数量为 1;不满足则返回失败且不标记已处理(后续轮询重试,见 5.7-2); saveFltr写入 Redis;- 非共享航班(
MAID == NULL)加入缓冲并发送 Kafkamsg; - 标记已处理(先于共享航班联动执行);
- 共享航班:向从 Redis 取出的主航班内存对象
MAFL追加MAFLDATA并将主航班加入缓冲(该修改仅作用于内存对象,未写回 Redis,见 5.7-14);主航班不存在时此处抛空指针。
- 校验
- 验收标准(现役可证实范围):
- 单条航班写入 Redis;
- 共享航班联动仅作用于发送缓冲中的主航班内存对象;Redis 内主航班记录不保证被同步更新(遗留缺陷,见 5.7-14);
- 通知与缓冲规则与动态航班一致(见 US-B1、US-B2)。
- 关联代码:
msghandler/schd/ADFTHandler.java。
US-A6 按 FLOP- 事件增量更新动态航班*
- 角色 / 期望 / 目标:作为上游,期望按
FLID下发指定事件的航班变更,以便动态航班库字段精确更新并同步前端。 - 触发条件:
META.TYPE=FLOP,STYP对应 29 个动态 Handler 之一。 - 处理流程:
FlopBaseHandler.run:- 按
FLID查询 Redis; - 航班存在:子类
updateFltr就地更新 →saveFltr写回 → 非共享航班加入缓冲并发送msg→ 标记已处理; - 航班不存在:标记已处理并返回失败。
- 按
- 验收标准:
- 仅当目标航班存在时执行更新;
- 更新结果写回 Redis;
- 共享航班自身不直接发送消息。
- 关联代码:
msghandler/flop/base/FlopBaseHandler.java及各覆写updateFltr的子类(清单见 5.3)。
US-A7 各 FLOP 子事件字段更新语义
- 说明:以下子事件语义依据各 Handler 实现代码核实;不表示均已具备自动化测试。现有测试仅覆盖 ABTM、CHOT、DELY、LACL、PSDT 五个子类型(
src/test/java/.../msghandler/flop/);ACTT、CNCL、FDEL 等关键路径无对应测试。按 29 个 STYP 建立「输入样本 × Redis 状态变更 × Kafka 通知」验收矩阵为新系统要求(见 6 节)。ACTT实际时间:FLTR.ACTT = FLOP.ACTT(ACTTHandler);ABTM靠桥 / 撤桥:按ABOP(A=靠桥,D=撤桥)在ABTM列表中定位同动作元素,存在则仅更新AOTM,不存在则新增(ABTMHandler);PSDT机位:机位相同则直接返回;否则将旧机位写入LPSDT、清空并写入新PSDT(机位号PSNO=0且无状态视为清空);随后按最后一个机位及基础数据计算abdg(PSDTHandler);DELY延误:清空旧延误;空CODE表示取消延误(同步清理ABN中的 DLY 元素);否则写入DELY并替换ABN中 DLY 元素(DELYHandler);CNCL取消:写入CNCL,并维护ABN中 CAN 元素(CNCLHandler);FDEL删除:见 US-A8。
- 其余子类型(FRET / PADT / CLDT / FTSS / TRML / FDIV / HNAG / STND / ROUT / RENO / BOTM / BDPB / REMC / VIPP / FLIN / LACL / ESTT / TAOP / GTDT / CKDT / FLTY / ACFT / CHOT)的字段更新逻辑以各自
updateFltr()实现为准。 - 关联代码:
msghandler/flop/*.java、src/test/java/.../msghandler/flop/*Test.java。
US-A8 删除动态航班(FLOP-FDEL)
- 角色 / 期望 / 目标:作为上游,期望通知某航班从运营计划中删除,以便本服务删除实时记录并通知前端同步删除。
- 处理流程:
FDELHandler.run:- 航班存在:
deleteFltr删除 Redis 记录 → 无条件发送删除消息至 Kafkamsg(不区分共享/非共享航班)→ 标记已处理; - 被删航班为共享航班:从内存中的主航班
MAFL移除对应元素并缓冲主航班(该修改未写回 Redis,见 5.7); - 航班不存在:标记已处理并返回失败。
- 航班存在:
- 验收标准(现役可证实范围):
- Redis 中对应
FLID被删除; - 被删航班为共享航班时:发送缓冲中主航班的
MAFL不再包含被删共享航班;Redis 内主航班记录不受该操作影响(遗留缺陷,见 5.7)。
- Redis 中对应
- 关联代码:
msghandler/flop/FDELHandler.java、service/flightInfo/FlightInfoServiceImpl.java。
EPIC-B 前端通知
US-B1 单条动态即时通知
- 角色 / 期望 / 目标:作为前端,期望在航班动态更新、删除或日计划完成时即时收到单条 JSON 消息,以便实时更新展示。
- 处理流程:
FlopBaseHandler.sendMsg/SchdBaseHandler.sendMsg|sendDschd→exchangeService.msgToJson(msg)→kafkaservice.msgSend("msg", json)。 - 验收标准:消息发送至主题
msg;动态与计划 Handler 中共享航班自身不触发单条通知。 - 例外(遗留行为):
FDELHandler对共享航班的删除同样发送msg删除消息(无条件调用sendMsg)。是否保留该通知语义由迁移决策确定(见 5.7)。 - 关联代码:
msghandler/flop/base/FlopBaseHandler.java、msghandler/schd/base/SchdBaseHandler.java、service/KafkaServiceImpl.java、service/exchange/ExchangeServiceImpl.java。
US-B2 批量缓冲定时下发
- 角色 / 期望 / 目标:作为前端,期望定期收到本窗口内变更航班的聚合消息,以便合并刷新并降低消息量。
- 处理流程:
FltrSendScheduled(cron*/3 * * * * ?)→takeAllFltr取空进程内队列 →JsonUtil.getString(fltrs)→ 发送至 Kafkaschd。 - 验收标准:消息发送至主题
schd,内容为FLTR数组 JSON;队列为空时不发送。 - 现役限制:
takeAllFltr先取空队列再发送,发送/序列化异常仅记录日志、不回灌,为 at-most-once(批次可能整体丢失),"定期收到"不保证可靠投递(见 3.5、5.7-17、6.2-5)。 - 关联代码:
scheduled/FltrSendScheduled.java、service/FltrSendBufferServiceImpl.java。
EPIC-C 日计划请求
US-C1 按时间范围发起日计划请求
- 角色 / 期望 / 目标:作为计划人员,期望提交时间范围,以登记一次日航班计划请求(RQFD 出站报文写入
COUTMSGS)。现役能力止于"登记出站意图",不含实际投递。 - 触发条件:
POST /schd/sync,请求体{startDate, endDate}(时间格式yyyy-MM-dd hh:mm)。 - 处理流程:
SchdController.sync(时间解析)→CmoutmsgServiceImpl.sendSchdGetMsg:SEQN = max(COUTMSGS_ID) + 1;- 构造
RQFD-NONE报文(RQFD.STDB/STDE格式ddMMMyyHHmm,大写); msgToXml序列化后写入COUTMSGS(ROUTINGID=OSH5RQFD)。
- 验收标准(现役可证实范围):
- 报文
META{SNDR=OSH5, TYPE=RQFD, STYP=NONE}且含时间段字段; COUTMSGS新增记录,XML 根元素为MSG并声明unisysaodbsis.xsd。
- 报文
- 现役实现约束(经代码核实):
- 控制器不校验
sendSchdGetMsg返回值; - 时间解析采用 12 小时制
hh(无 AM/PM 标记),空值、区间合法性与解析失败均无校验; - 工程内无
COUTMSGS读取/发送执行器(见 3.9)。
- 控制器不校验
- 迁移要求:新系统须显式定义投递责任与出站状态机,提供重试与可观测性;时间格式改为 24 小时制(
HH);对时间空值、区间及解析失败做输入校验(见 6 节)。 - 关联代码:
controller/SchdController.java、service/CmoutmsgServiceImpl.java、entity/msg/builder/MSGBuilder.java、entity/msg/builder/METABuilder.java。
EPIC-D 历史与归档
US-D1 每日归档过期入站报文
- 角色 / 期望 / 目标:作为系统,期望在每日固定时间将接收超过一天的
CMINMSGS转入历史表并清理原表,以控制主表数据量。 - 处理流程:
CminmsgsHisScheduled(cron0 0 3 * * ?)→CminmsgHstDao.moveToHistory(INSERT...SELECT NOT EXISTS + DELETE,单事务)。 - 验收标准:
cminmsgs_hst增加符合条件记录(列见 5.5);- 原表删除一天前的记录;
- 历史表中已存在的 ID 不重复归档。
- 关联代码:
scheduled/CminmsgsHisScheduled.java、dao/CminmsgHstDaoImpl.java。
US-D2 每日将过期动态航班写入历史索引
- 角色 / 期望 / 目标:作为系统,期望将已结束运营的航班从实时库转入 Elasticsearch 历史库,以便历史查询可用并保持实时库精简。
- 处理流程:
FlightHisScheduled(cron0 30 3 * * ?)→findAll→getHisToBeTran(判定条件见 3.7)→FlightHisServiceImpl.save(按SODT + FLIDupsert 至flight_hts)→ 成功航班从 Redis 删除。 - 验收标准:
- 满足任一历史条件的航班写入 ES;
- 仅写入成功的航班从 Redis 删除;
- "单条失败不影响其他航班"仅适用于 ES 写入阶段(
save循环逐条捕获异常);getHisToBeTran资格判定阶段未逐条隔离,空/非法时间字段会中断当次整批(见 3.7、5.7-18)。
- 关联代码:
scheduled/FlightHisScheduled.java、service/flightInfo/FlightHisServiceImpl.java、elasticsearch/ElasticsearchUtil.java、service/flightInfo/FlightInfoServiceImpl.java。
US-D3 一次性历史索引迁移
- 角色 / 期望 / 目标:作为运维,期望将
flight_hts全量历史迁移至新索引flight_hts2,以完成索引结构变更。 - 触发条件:
GET /flights/migrate。 - 处理流程:scroll 全量读取
flight_hts→transToNewFltrs(还原ABN子对象 DLY / CAN / RTN / ALT)→ 逐条写入flight_hts2。 - 验收标准:数据完整写入
flight_hts2,异常子对象还原正确。 - 关联代码:
controller/FlightsController.java(migrateFlightHst / transToNewFltrs / mapToDly)。
EPIC-E 实时查询与基础数据
US-E1 查询全部最新动态航班
- 角色 / 期望 / 目标:作为前端或调用方,期望获取当前全量动态航班(不含共享航班),以便页面渲染。
- 触发条件:
GET /all/flights。 - 处理流程:
findAll(Redis hmget)→ 过滤掉共享航班(MAID != NULL)→ResponseDto.success。 - 验收标准:返回结果不含共享航班记录,内容与 Redis
flightInfo一致。 - 关联代码:
controller/FlightsController.java、service/flightInfo/FlightInfoServiceImpl.java。
US-E2 以机位与登机桥基础数据完善动态航班
- 角色 / 期望 / 目标:作为系统,期望依据计划机位获取机位类型与登机桥编码,以生成动态航班的登机桥字段。
- 处理流程:
PSDTHandler.updateAbg→OrmsStandManager/OrmsStandAirbridgeManager(读取 Redis 缓存,未命中时经RestTemplate调用 admin-api)。 - 验收标准:近机位(
standType = near)生成abdg;远机位或清空机位消息时abdg为空。 - 关联代码:
basicdata/manager/OrmsStandManager.java、basicdata/manager/OrmsStandAirbridgeManager.java、basicdata/service/OrmsStandServiceImpl.java、msghandler/flop/PSDTHandler.java。
EPIC-F 运维工具
US-F1 转发报文至指定 Kafka 主题
- 角色 / 期望 / 目标:作为运维,期望将 JSON 或 XML 报文发送至指定主题,以支持联调、补发与压测。
- 触发条件:
POST /kafka/topics/{name}/msgs。 - 处理流程:请求体按 JSON 解析成功则直接发送;失败则按 XML 解析为
MSG后转 JSON 发送。 - 验收标准:JSON 直发;XML 解析后发送;两种输入均返回成功响应。
- 关联代码:
controller/KafkaController.java、utils/JsonUtil.java、service/exchange/ExchangeServiceImpl.java。
US-F2 服务启动即开始消息处理
- 角色 / 期望 / 目标:作为运维,期望服务启动后自动开始消息轮询处理,无需人工干预。
- 触发条件:应用启动(
CommandLineRunner执行完成)。 - 处理流程:
AppRunner.run(CommandLineRunner)→MsgExchangeServiceImpl.start。 - 验收标准:启动后即按
msgExchange.intervalSeconds周期开始轮询并分派未处理报文(见 US-A2)。 - 关联代码:
runner/AppRunner.java。
5. 附录
5.1 HTTP 接口清单
| 方法 / 路径 | 请求体 | 响应(ResponseDto) | 功能 | 实现 |
|---|---|---|---|---|
POST /cminmsgs/send |
XML 文本 | body=CMINMSGS_ID |
收报入库 | CminmsgsController |
POST /schd/sync |
{startDate, endDate} |
成功 | 构造 RQFD-NONE 报文并写入 COUTMSGS | SchdController |
GET /all/flights |
— | body=List<SCHD.FLTR>(非共享) |
全量动态航班查询 | FlightsController |
GET /flights/migrate |
— | 成功 | 迁移 flight_hts 至 flight_hts2 |
FlightsController |
POST /kafka/topics/{name}/msgs |
JSON 或 XML | 成功 | 转发至指定 Kafka 主题 | KafkaController |
统一响应封装:dto/ResponseDto.java(字段 is_success、err_code、err_msg、body)与 enums/ResultCode.java。
5.2 定时任务与后台线程
| 名称 | 周期(配置 key) | 行为 | 实现 |
|---|---|---|---|
| 消息轮询处理 | msgExchange.intervalSeconds(各环境均配置为 1 秒,代码无默认值) |
采集未处理 CMINMSGS 并分派 | AppRunner、MsgExchangeServiceImpl、MsgExchangeRunner |
| 入站报文历史归档 | scheduled.cminmsgHisCron(0 0 3 * * ?) |
一天前报文转 CMINMSGS_HST 并清理 |
CminmsgsHisScheduled |
| 动态航班转历史 | scheduled.flightInfoCron(0 30 3 * * ?) |
过期航班写 ES flight_hts,从 Redis 删除 |
FlightHisScheduled |
| 缓冲批量发送 | scheduled.flightSendCron(*/3 * * * * ?) |
取空缓冲并发送 Kafka schd |
FltrSendScheduled |
| 异步执行线程池 | scheduled.corePoolSize / maxPoolSize / queueCapacity |
定时任务异步执行 | config/ScheduledAsyncConfig.java |
5.3 消息类型与 Handler 清单
计划类(msghandler/schd/,继承 SchdBaseHandler):
| STYP | Handler | 行为 |
|---|---|---|
| RESP | RESPHandler |
日计划快照刷新、通知、标记已处理;失败时重试 |
| DNLD | DNLDHandler |
同 RESP |
| ADFT | ADFTHandler |
添加单条计划外航班并联动共享航班 |
动态类(msghandler/flop/,共 29 个,继承 FlopBaseHandler;除 FDEL 覆写 run 外,其余覆写 updateFltr):
ABTM、FRET、PADT、ACTT、PSDT、CLDT、FTSS、TRML、FDEL、FDIV、HNAG、STND、DELY、ROUT、RENO、BOTM、CNCL、BDPB、REMC、VIPP、FLIN、LACL、ESTT、TAOP、GTDT、CKDT、FLTY、ACFT、CHOT
已核实语义:ACTT 实际时间、ABTM 靠 / 撤桥时间、PSDT 机位、DELY 延误、CNCL 取消、FDEL 删除;其余子类型以各自 updateFltr() 实现及 SIS 规范为准。
忽略清单默认值:dev / local / pro = ldm-*,regn-*,rsta-*,eror-*;test = ldm-*,regn-*,rsta-*,error-*。
5.4 配置项(示例取自 application-dev.yml)
spring.jpa:ddl-auto=none;物理命名策略PhysicalNamingStrategyStandardImpl。spring.datasource:MySQL,库cdairport。spring.redis.cluster:nodes / password / pool。kafka.producer.*:servers、retries=0、linger=1、batch、buffer、max-request;kafka.consumer.*:含 zookeeper 遗留配置,无监听器使用。msgExchange:intervalSeconds=1、ignoreMsg;waitDateLeftOffset=600000(各环境均有配置,但 Java 代码零引用,未被使用,迁移时可剔除)。logstash.host:dev =hz011.int.it2000.com.cn:5555;local = test =130.120.3.234:5000;pro =172.17.35.160:5000(application-pro.yml:60,与 local/test 不同)。scheduled:flightInfoCron=0 30 3 * * ?、cminmsgHisCron=0 0 3 * * ?、flightSendCron=*/3 * * * * ?、corePoolSize=10、maxPoolSize=50、queueCapacity=10。hstCondition(单位毫秒):ARRIVE_HST_TIME=3600000(1 小时)、CANCEL_HST_TIME=3600000(1 小时)、FDIV_HST_TIME=59400000、SODT_HST_TIME=259200000(3 天)。elasticsearch:ip / port=9300 / pool=5 / cluster.name(dev =opensearch)/ nodes。eureka.client.service-url.defaultZone;eureka.instance.hostName/prefer-ip-address。adminApi:schema / baseUrl(dev、test、pro 使用服务名ADMINAPI;仅 local 使用 host:port130.120.3.231:92)、ormsStandsUrl、getAirbridgeCodeByStandCodeUrl。
5.5 数据表列清单(实体映射)
CMINMSGS(entity/Cminmsg.java):CMINMSGS_ID、CMINMSGS_CLOB_MSG、CMINMSGS_DATE_PROCESSED、CMINMSGS_DATE_RECEIVED、CMINMSGS_STATUS、CMINMSGS_SUBSYSTEM_DATE_SENT、CMINMSGS_SUBSYSTEM_NAME、CMINMSGS_SUBSYSTEM_SEQUENCE、CMINMSGS_SUBSYSTEM_SUBTYPE、CMINMSGS_SUBSYSTEM_TYPE。
CMINMSGS_HST(entity/CminmsgHst.java)与 CMINMSGS_TEST(entity/CminmsgTest.java):列同上。
COUTMSGS(entity/Cmoutmsg.java):COUTMSGS_ID、COUTMSGS_ACK_DATE_RECV、COUTMSGS_ACK_REQD、COUTMSGS_ACK_RESEND_TIMES、COUTMSGS_CLOB_MSG、COUTMSGS_DATE_INSERTED、COUTMSGS_DATE_SENT、COUTMSGS_ENCRYPT、COUTMSGS_ERROR、COUTMSGS_FINAL_GROUP_IND、COUTMSGS_GROUP_ID、COUTMSGS_GROUP_ORDER、COUTMSGS_NO_MESSAGES、COUTMSGS_TRUEFALS_GROUP、ROUTINGID。
5.6 Redis key 汇总
| key | 结构 | 内容 | 维护方式 |
|---|---|---|---|
flightInfo |
hash:FLID → FLTR | 动态航班实时库 | 日计划合并写入(hmset = putAll,不清理差集)/ 动态增量 / 转历史后删除 |
orms_stand |
hash:standCode → OrmsStand | 机位基础数据 | 未命中时全量拉取并写入,过期 3600 秒 |
orms_stand_airbridge |
hash:standCode → JSON 数组字符串 | 机位与登机桥关系 | 逐机位懒加载写入,过期 3600 秒 |
5.7 实现特征与已知问题
以下为经代码核实的实现特征,供新系统设计对照:
- Handler 由 Dispatcher 反射实例化(非 Spring Bean),依赖经
SpringUtil手动获取;分派通过反射调用run。 - 处理标记不区分成功与失败:Handler 内部失败亦标记已处理;不标记分支包括 RESP / DNLD 刷新失败(
updateByDaySchd返回 false)与 ADFT 数量校验失败(直接HandlerResult.failure())。这些消息按轮询周期持续重试,无显式重试上限/死信;每日 3:00 归档任务按CMINMSGS_DATE_RECEIVED < 1 天将其移入历史表并删除(重试窗口约 1 天,见 3.6)。 - XML 解析与序列化基于 Jackson XML(JAXB 注解 introspection);
msgToXml/msgToJson通过反射get{TYPE}()获取业务体;xmlToMsg含 BDPB 空元素兼容处理。 - RedisTemplate 启用 Jackson
enableDefaultTyping;orms_stand_airbridge的值为 JSON 字符串(存在二次编码)。 - JSON 处理并存两套工具:
JsonUtil(Jackson)与 fastjsonJSONObject(ES 写入、FlightsController);部分控制器直接实例化ObjectMapper。 CmoutmsgHstServiceImpl的CMINMSGS_ID % 10分表归档逻辑及insertToTable仍保留,但未被当前定时任务使用(现使用单表cminmsgs_hst与moveToHistory)。- Kafka 仅生产不消费;
kafka.consumer.*与 zookeeper 配置无消费方;业务主题固定为msg、schd。 COUTMSGS仅写入无读取;/schd/sync产物无发送执行器(见 3.9)。- 明文口令直接存放于各环境
application-*.yml;默认激活环境为 dev(spring.profiles.active=dev)。 - 忽略清单在 test 环境配置为
error-*,与其他环境(eror-*)不一致。 hstCondition各阈值按毫秒计算(配置注释亦为毫秒),而相关代码注释存在单位表述不一致。updateByDaySchd经RedisService.hmset(putAll)合并写入;该实现细节仅描述 legacy 行为。FDELHandler对共享航班的删除同样调用sendMsg发送msg删除消息(与"共享航班不直接发送"的通用规则不一致)。FDELHandler删除共享航班、ADFTHandler添加共享航班时,对主航班MAFL的修改均仅作用于内存对象并进入发送缓冲,未调用saveFltr写回 Redis;FDEL 元素比对使用==(MAFLDATA.getFlid()与FLTR.getFLID()均为BigInteger,故为引用比较而非值比较)。属遗留缺陷,新系统应采用值相等比较并在同一原子状态变更中持久化主/共享航班关系。/schd/sync时间解析使用 12 小时制hh(无 AM/PM 标记),且对空值、区间、解析失败及服务返回值均无校验。updatefltrBridge对ABDG为按序直接追加,代码不插入分隔符(分隔符依赖数据自身是否带逗号),仅当拼接结果以逗号结尾时删除末尾一个逗号(见 3.3)。- Kafka 批量缓冲(主题
schd)为 at-most-once:FltrSendScheduled调takeAllFltr先取空进程内队列,序列化或发送异常仅记录日志、不回灌队列,该批消息可能整体丢失(见 3.5、US-B2)。 FlightHisServiceImpl.getHisToBeTran(资格判定)未对单条航班做异常隔离:SODT缺失/非法(四个判定方法均无空值保护直接解析)、ACTT/CNCL非空但格式非法、MVIN为空且ACTT存在(isDMatch/isAMatch 的equalsNPE)等任一条异常都会由FlightHisScheduled外层捕获并中断当次整批,剩余航班不再处理;仅save(ES 写入)循环逐条捕获异常(见 3.7、US-D2)。
6. 迁移验收边界(评审并入)
本节内容依据 Plane ACMA-4 评审意见整理,用于区分"现役行为"(正文与附录的描述对象)与"新系统验收要求"(本节),避免迁移对拍时把待实现语义当作现役事实。
6.1 类别区分
- 现役行为:文档正文与附录所描述内容,均可经"关联代码"复核。
- 迁移目标:新系统须显式实现的能力(见 6.2),不以现役实现为上限。
- 待确认外部契约:
COUTMSGS投递通道与协议(3.9)、搜索集群类型(ES 或 OpenSearch,见 5.4)、前端对 FDEL 通知语义的依赖(US-B1 例外)。
6.2 迁移验收边界
- 日计划语义:新系统的日计划处理规则以 航班域 为准,不从 legacy Redis 行为推导。
- 共享航班增删链路:决定保留或消除 FDEL 对共享航班的通知(US-B1 例外);主/共享航班关系(ADFT 添加、FDEL 删除)须在同一原子状态变更中持久化(修复 ADFT/FDEL 未写回与 FDEL
==引用比较缺陷,见 5.7-14)。 - 可执行验收矩阵:覆盖 3 个 SCHD 与 29 个 FLOP 子类型,维度为「输入样本 × Redis 状态变更 × Kafka 通知结果」;对当前无测试的关键路径(如 ACTT、CNCL、FDEL、RESP、DNLD、ADFT)补自动化用例。
- 入站可靠性:每类消息的幂等键、重复投递与多实例并发行为。
- 失败处理:解析、业务、Kafka、Redis、ES 失败的分类、重试上限、死信与人工重放。
- 一致性:跨 MySQL、Redis、Kafka、ES 的一致性与可恢复性约束。
- 契约:消息顺序、共享航班更新与前端可观察事件的契约测试。
- 安全基线:移除
application-*.yml明文凭据与 Redis 默认多态反序列化(enableDefaultTyping)。
6.3 评审采纳记录
| ACMA-4 评审意见 | 处理 | 文档落点 |
|---|---|---|
| 1 日计划"整体覆盖"表述不符 | 采纳,改为合并写入语义 | 3.3、US-A4、5.6、5.7-12、6.2-1 |
| 2 FDEL 共享航班亦发送通知 | 采纳,标注例外 | 3.4、US-A8、US-B1、5.7-13、6.2-2 |
| 3 共享航班删除关系不保证持久化 | 采纳,标注遗留缺陷 | 3.4、US-A8、5.7-14、6.2-2 |
| 4 测试覆盖声明过度 | 采纳,区分"语义核实"与"测试覆盖" | US-A7、5.7、6.2-3 |
| 5 RQFD 故事业务承诺超出现役 | 采纳,改为"登记出站意图" | US-C1、3.9、5.7-15、6.2 |
| 补充验收边界 | 采纳 | 6.2、6.3 |
6.4 第二轮评审采纳记录(2026-09-03 ZCode 自动评审 + 二次全面复审)
| 评审项 | 处理 | 文档落点 |
|---|---|---|
| 1 logstash.host pro 环境值错误 | 采纳,pro = 172.17.35.160:5000 |
5.4 |
| 2 adminApi.baseUrl test 环境应为服务名 | 采纳,dev/test/pro 用 ADMINAPI,仅 local 用 host:port |
5.4 |
| 3 ADFT 数量校验失败不标记、持续重试 | 采纳,纳入"不标记"分支,区分抛异常/返回失败 | 3.3、US-A2、US-A5、5.7-2 |
| 4 ADFT 共享航班联动同样不持久化主航班 MAFL | 采纳,扩展 5.7-14 为 ADFT/FDEL;验收收敛为缓冲对象 | 3.3、US-A5、5.7-14、6.2-2 |
| 5 abdg 拼接机制为按序直接追加 | 采纳,改写 3.3 与 US-A4 验收 | 3.3、US-A4、5.7-16 |
6 FDEL == 为 BigInteger 引用比较 |
采纳,修正 Long 表述 | 3.4、5.7-14 |
| 7 ADFT 标记已处理先于共享联动 | 采纳,按代码顺序重写 | 3.3、US-A5 |
| 8 端口 8080 为隐式缺省 | 采纳,注明无 server.port 配置 | 1 节 |
| 9 附录 C/D/E 悬空引用 | 采纳,改为 5.3/5.4/5.5 | 2、3.4、3.7、US-A6、US-D1、6.1 |
| 10 US-A5 缺触发条件、US-F2 缺验收标准 | 采纳,补齐格式字段 | US-A5、US-F2 |
| 11 waitDateLeftOffset 未被使用 | 采纳,标注未使用 | 5.4 |
| 12 失败消息隐式重试至归档(约 1 天窗口) | 采纳,补充说明 | 5.7-2、3.6 |
| 二次全面复审:批量 Kafka 通知为 at-most-once | 采纳,标注现役限制 | 3.5、US-B2、5.7-17、6.2-5 |
| 二次全面复审:历史资格判定坏数据中断整批 | 采纳,收窄验收至 ES 写入阶段 | 3.7、US-D2、5.7-18 |
| R1 5.7-18/3.7 坏数据举例不精确(SODT 无保护、ACTT 缺失有保护、MVIN 空 NPE) | 采纳,按代码实况改述 | 3.7、5.7-18 |
| R2 "默认 1 秒"实为各环境配置值(代码无默认) | 采纳,改为"各环境均配置 1 秒、代码无默认值" | 3.2、US-A2、5.2 |
| R3 US-A5 触发条件括注移入流程约束;2 节补 ADFT 失败示例 | 采纳 | US-A5、2 节 |
本节与新系统实施计划(ACMA-3)同步维护;迁移实施 issue 仅引用本修订版用户故事作为一致性对拍基线。6.4 采纳记录含首轮(6.3)、第二轮与第三轮(R1–R3)评审意见的落点,正文与附录均以修订后描述为准。