feat: 新增 G4 热表独立双写能力

- 新增配置项以支持旧/新明细表的独立写入开关及目标表名。
- 重构 DatabaseManager,抽象通用批量 COPY 写入内核,支持不同目标表的复用。
- 新增双明细写入编排器,支持旧/新表独立执行、重试及 fallback。
- 调整 HeartbeatProcessor.processBatch(),确保 room_status 独立执行。
- 错误表仅记录新表写入失败,旧表失败不再写入错误表。
- 重新定义消费暂停策略,基于当前启用的关键 sink 判断。
- 补充按 sink 维度的统计项与启动日志。

新增 G4 热表相关的数据库规范与处理逻辑,确保系统在双写模式下的稳定性与可扩展性。
This commit is contained in:
2026-03-09 15:49:12 +08:00
parent f59000f5ef
commit 43fa7505e5
21 changed files with 2546 additions and 154 deletions

View File

@@ -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>?