feat: 新增 G4 热表独立双写能力
- 新增配置项以支持旧/新明细表的独立写入开关及目标表名。 - 重构 DatabaseManager,抽象通用批量 COPY 写入内核,支持不同目标表的复用。 - 新增双明细写入编排器,支持旧/新表独立执行、重试及 fallback。 - 调整 HeartbeatProcessor.processBatch(),确保 room_status 独立执行。 - 错误表仅记录新表写入失败,旧表失败不再写入错误表。 - 重新定义消费暂停策略,基于当前启用的关键 sink 判断。 - 补充按 sink 维度的统计项与启动日志。 新增 G4 热表相关的数据库规范与处理逻辑,确保系统在双写模式下的稳定性与可扩展性。
This commit is contained in:
@@ -102,6 +102,99 @@
|
||||
- **AND** 调用后应重试当前批次写入
|
||||
- **AND** 系统不应在运行时创建或替换数据库 schema 对象
|
||||
|
||||
### Requirement: G4 热表独立写入能力
|
||||
系统 MUST 支持向 `heartbeat.heartbeat_events_g4_hot` 分区表执行批量 COPY 写入,并与旧表 `heartbeat.heartbeat_events` 共享同一套通用写入内核。
|
||||
|
||||
#### Scenario: G4 热表批量 COPY 写入
|
||||
- **WHEN** `g4HotHeartbeatEnabled=true` 且有一批心跳数据待写入
|
||||
- **THEN** 系统应使用批量 COPY 将数据写入 `heartbeat.heartbeat_events_g4_hot`
|
||||
- **AND** 写入流程应与旧表共享同一通用写入内核
|
||||
|
||||
#### Scenario: G4 热表分区由外部维护
|
||||
- **WHEN** 写入 `heartbeat.heartbeat_events_g4_hot`
|
||||
- **THEN** 系统不应在运行时为该表执行分区预创建、缺分区补建或其他分区维护逻辑
|
||||
- **AND** 分区应由外部脚本或外部调度系统维护
|
||||
|
||||
#### Scenario: G4 热表 COPY 失败降级
|
||||
- **WHEN** G4 热表批量 COPY 写入失败且重试次数耗尽
|
||||
- **THEN** 系统应降级为逐条 INSERT 写入
|
||||
- **AND** 单条失败不影响同批次其他记录
|
||||
|
||||
### Requirement: G4 热表 guid 写入规则
|
||||
系统 MUST 在写入 `heartbeat.heartbeat_events_g4_hot` 时为每条记录提供 `guid` 字段值,格式为无连接符的小写 GUID。
|
||||
|
||||
#### Scenario: 缺失 guid 时自动生成
|
||||
- **WHEN** 待写入记录未提供 `guid`
|
||||
- **THEN** 系统应为该记录生成一个新的 GUID
|
||||
- **AND** 生成结果应为 32 位十六进制小写字符串
|
||||
- **AND** 结果中不应包含 `-`
|
||||
|
||||
#### Scenario: 已提供 guid 时规范化
|
||||
- **WHEN** 待写入记录已提供 `guid`
|
||||
- **THEN** 系统应将该值转换为小写
|
||||
- **AND** 应去除其中的 `-`
|
||||
- **AND** 规范化后的值应写入 `heartbeat.heartbeat_events_g4_hot`
|
||||
|
||||
### Requirement: G4 热表 power 辅助字段当前阶段写空
|
||||
系统 MUST 在当前阶段将 `power_carbon_on`、`power_carbon_off`、`power_person_exist`、`power_person_left` 固定写为 `null`,待后续计算逻辑接入后再启用实际赋值。
|
||||
|
||||
#### Scenario: 当前阶段统一写 null
|
||||
- **WHEN** 系统写入 `heartbeat.heartbeat_events_g4_hot`
|
||||
- **THEN** `power_carbon_on` 应写入 `null`
|
||||
- **AND** `power_carbon_off` 应写入 `null`
|
||||
- **AND** `power_person_exist` 应写入 `null`
|
||||
- **AND** `power_person_left` 应写入 `null`
|
||||
- **AND** 不应从来源数据的 `extra` 或其他字段提取这 4 个值
|
||||
|
||||
### Requirement: 双明细独立编排
|
||||
系统 MUST 提供双明细写入编排能力,按启动配置分别控制旧表与 G4 热表的写入,两路写入结果完全独立。
|
||||
|
||||
#### Scenario: 仅旧表开启
|
||||
- **WHEN** `legacyHeartbeatEnabled=true` 且 `g4HotHeartbeatEnabled=false`
|
||||
- **THEN** 系统应仅写入旧表 `heartbeat.heartbeat_events`
|
||||
- **AND** 不应尝试写入 G4 热表
|
||||
|
||||
#### Scenario: 仅新表开启
|
||||
- **WHEN** `legacyHeartbeatEnabled=false` 且 `g4HotHeartbeatEnabled=true`
|
||||
- **THEN** 系统应仅写入 G4 热表 `heartbeat.heartbeat_events_g4_hot`
|
||||
- **AND** 不应尝试写入旧表
|
||||
|
||||
#### Scenario: 双写模式
|
||||
- **WHEN** `legacyHeartbeatEnabled=true` 且 `g4HotHeartbeatEnabled=true`
|
||||
- **THEN** 系统应分别写入旧表与 G4 热表
|
||||
- **AND** 旧表写入失败不影响 G4 热表写入
|
||||
- **AND** G4 热表写入失败不影响旧表写入
|
||||
|
||||
#### Scenario: 双关模式
|
||||
- **WHEN** `legacyHeartbeatEnabled=false` 且 `g4HotHeartbeatEnabled=false`
|
||||
- **THEN** 系统应跳过所有明细写入
|
||||
- **AND** 不应报错或阻止消费
|
||||
|
||||
### Requirement: 写入目标启动配置
|
||||
系统 MUST 通过启动配置(环境变量)分别控制旧表、G4 热表和 room_status 的写入开关与目标表名。
|
||||
|
||||
#### Scenario: 配置加载
|
||||
- **WHEN** 系统启动时
|
||||
- **THEN** 应从环境变量读取 `DB_LEGACY_HEARTBEAT_ENABLED`(默认 true)、`DB_G4_HOT_HEARTBEAT_ENABLED`(默认 false)、`DB_ROOM_STATUS_ENABLED`(默认 true)
|
||||
- **AND** 应从环境变量读取 `DB_LEGACY_TABLE`(默认 `heartbeat.heartbeat_events`)、`DB_G4_HOT_TABLE`(默认 `heartbeat.heartbeat_events_g4_hot`)
|
||||
|
||||
#### Scenario: 启动日志输出配置摘要
|
||||
- **WHEN** 系统启动完成时
|
||||
- **THEN** 应在日志中输出旧/新明细写入开关状态、目标表名和 room_status 开关状态
|
||||
|
||||
### Requirement: 错误表仅服务 G4 热表
|
||||
系统 MUST 将 `heartbeat.heartbeat_events_errors` 仅用于记录 G4 热表写入失败的记录,旧表写入失败不写入错误表。
|
||||
|
||||
#### Scenario: G4 热表写入失败记录错误
|
||||
- **WHEN** G4 热表写入产生失败记录
|
||||
- **THEN** 系统应将失败记录写入 `heartbeat.heartbeat_events_errors`
|
||||
- **AND** 错误表字段和结构不变
|
||||
|
||||
#### Scenario: 旧表写入失败不记录错误表
|
||||
- **WHEN** 旧表写入产生失败记录
|
||||
- **THEN** 系统不应将失败记录写入 `heartbeat.heartbeat_events_errors`
|
||||
- **AND** 应仅记录日志/统计
|
||||
|
||||
### Requirement: 建库与分区维护能力必须以外部脚本提供
|
||||
系统 MUST 在仓库根目录 `SQL_Script/` 提供可被外部程序调用的建库/分区维护脚本。
|
||||
|
||||
|
||||
@@ -94,6 +94,50 @@
|
||||
- **THEN** 系统应继续写入同批次其他合法记录
|
||||
- **AND** 失败记录应按错误日志规则写入 Redis 项目控制台
|
||||
|
||||
### Requirement: room_status 独立执行
|
||||
系统 MUST 在批次处理中始终独立执行 room_status 同步,不依赖任何明细写入的成功与否。
|
||||
|
||||
#### Scenario: room_status 始终独立执行
|
||||
- **WHEN** 一批心跳数据完成验证与转换
|
||||
- **THEN** 系统应始终调用 room_status 的 upsert 同步逻辑(当 `roomStatusEnabled=true`)
|
||||
- **AND** 不依赖旧表明细写入是否开启
|
||||
- **AND** 不依赖新表明细写入是否开启
|
||||
- **AND** 不依赖旧/新表写入是否成功
|
||||
- **AND** 同步失败不应阻塞主处理流程
|
||||
|
||||
#### Scenario: 明细双关仍写 room_status
|
||||
- **WHEN** `legacyHeartbeatEnabled=false` 且 `g4HotHeartbeatEnabled=false` 且 `roomStatusEnabled=true`
|
||||
- **THEN** 系统仍应对当前批次数据执行 room_status upsert
|
||||
- **AND** Kafka 消费不应因明细双关而暂停
|
||||
|
||||
### Requirement: 区分旧新目标失败处理
|
||||
系统 MUST 在批量写库时区分旧表与 G4 热表的失败处理路径。
|
||||
|
||||
#### Scenario: 新表失败记录写入错误表
|
||||
- **WHEN** G4 热表批量写入中存在失败记录
|
||||
- **THEN** 系统应将失败记录写入 `heartbeat.heartbeat_events_errors`
|
||||
|
||||
#### Scenario: 旧表失败记录不写入错误表
|
||||
- **WHEN** 旧表批量写入中存在失败记录
|
||||
- **THEN** 系统不应将失败记录写入 `heartbeat.heartbeat_events_errors`
|
||||
- **AND** 应仅记录日志与统计
|
||||
|
||||
### Requirement: 按 sink 维度的统计与监控
|
||||
系统 MUST 按写入目标维度分别统计成功数、失败数与降级事件。
|
||||
|
||||
#### Scenario: legacy 与 g4Hot 分别统计
|
||||
- **WHEN** 系统完成一批次的双写编排
|
||||
- **THEN** 应分别统计 legacy 写入成功数、失败数
|
||||
- **AND** 应分别统计 g4Hot 写入成功数、失败数
|
||||
- **AND** 统计项应在 Redis 控制台输出或 stats 汇总中可见
|
||||
|
||||
#### Scenario: 启动时输出双写配置摘要
|
||||
- **WHEN** 服务完成数据库连接并进入启动阶段
|
||||
- **THEN** 系统应输出双写配置摘要
|
||||
- **AND** 摘要中应包含 legacy 开关与目标表
|
||||
- **AND** 摘要中应包含 g4Hot 开关与目标表
|
||||
- **AND** 摘要中应包含 room_status 开关
|
||||
|
||||
## ADDED Requirements
|
||||
### Requirement: 数组字段聚合为列数组
|
||||
系统 SHALL <20>?`electricity[]` <20>?`air_conditioner[]` 按原始顺序聚合为数据库写入结构的列数组<E695B0>?
|
||||
|
||||
Reference in New Issue
Block a user