feat: 添加 G5 状态表同步开关,默认关闭写入功能并更新相关配置和文档

This commit is contained in:
2026-03-24 08:34:36 +08:00
parent fa363835a3
commit 7713cfeb9e
8 changed files with 80 additions and 6 deletions

View File

@@ -49,3 +49,7 @@ REDIS_PASSWORD=
REDIS_DB=15 REDIS_DB=15
REDIS_CONNECT_TIMEOUT_MS=5000 REDIS_CONNECT_TIMEOUT_MS=5000
REDIS_PROJECT_NAME=bls-onoffline REDIS_PROJECT_NAME=bls-onoffline
# G5 room_status.moment sync
# false: do not write room_status.room_status_moment_g5
G5_ROOM_STATUS_MOMENT_SYNC_ENABLED=false

View File

@@ -29,3 +29,7 @@ REDIS_PASSWORD=
REDIS_DB=0 REDIS_DB=0
REDIS_PROJECT_NAME=bls-onoffline REDIS_PROJECT_NAME=bls-onoffline
REDIS_API_BASE_URL=http://localhost:3001 REDIS_API_BASE_URL=http://localhost:3001
# G5 room_status.moment sync
# false: do not write room_status.room_status_moment_g5
G5_ROOM_STATUS_MOMENT_SYNC_ENABLED=false

View File

@@ -0,0 +1,13 @@
# Change: add g5 room status sync toggle
## Why
当前 G5 `room_status.room_status_moment_g5` 同步是默认启用的,但新的运行要求需要默认关闭,避免未经确认就写入状态表。
## What Changes
- 新增一个环境变量开关,控制是否同步写入 G5 `room_status.room_status_moment_g5`
- 默认值为 `false`,即不写入该表。
- 当开关开启时,保留现有按 `hotel_id + room_id` upsert 更新 `ip` 的行为。
## Impact
- Affected specs: `openspec/specs/onoffline/spec.md`
- Affected code: `src/config/config.js`, `src/index.js`, `.env`, `.env.example`

View File

@@ -0,0 +1,14 @@
## ADDED Requirements
### Requirement: G5 状态表同步开关
系统 SHALL 提供一个环境变量开关,用于控制是否向 G5 状态表 `room_status.room_status_moment_g5` 写入数据;该开关默认值 SHALL 为 `false`
#### Scenario: 默认关闭
- **GIVEN** 未设置 G5 状态表同步开关
- **WHEN** 服务启动并处理 Kafka 消息
- **THEN** 系统不向 `room_status.room_status_moment_g5` 写入数据
#### Scenario: 显式开启
- **GIVEN** G5 状态表同步开关被设置为 `true`
- **WHEN** 服务处理 Kafka 消息
- **THEN** 系统恢复向 `room_status.room_status_moment_g5` 写入数据

View File

@@ -0,0 +1,11 @@
## 1. Implementation
- [x] 1.1 Add a config flag for G5 room_status synchronization.
- [x] 1.2 Disable `room_status.room_status_moment_g5` writes by default.
- [x] 1.3 Keep the existing upsert behavior when the flag is enabled.
- [x] 1.4 Update environment samples to set the flag to `false`.
## 2. Validation
- [x] 2.1 Run `npm run lint`.
- [x] 2.2 Run `npm run test`.
- [x] 2.3 Run `npm run build`.
- [x] 2.4 Run `openspec validate add-g5-room-status-sync-toggle --strict`.

View File

@@ -106,3 +106,16 @@
- **WHEN** 服务处理该错误 - **WHEN** 服务处理该错误
- **THEN** 服务记录错误并按既有错误处理机制处理,不在运行时执行分区创建 - **THEN** 服务记录错误并按既有错误处理机制处理,不在运行时执行分区创建
### Requirement: G5 状态表同步开关
系统 SHALL 提供一个环境变量开关,用于控制是否向 G5 状态表 `room_status.room_status_moment_g5` 写入数据;该开关默认值 SHALL 为 `false`
#### Scenario: 默认关闭
- **GIVEN** 未设置 G5 状态表同步开关
- **WHEN** 服务启动并处理 Kafka 消息
- **THEN** 系统不向 `room_status.room_status_moment_g5` 写入数据
#### Scenario: 显式开启
- **GIVEN** G5 状态表同步开关被设置为 `true`
- **WHEN** 服务处理 Kafka 消息
- **THEN** 系统恢复向 `room_status.room_status_moment_g5` 写入数据

View File

@@ -13,6 +13,12 @@ const parseList = (value) =>
.map((item) => item.trim()) .map((item) => item.trim())
.filter(Boolean); .filter(Boolean);
const parseBoolean = (value, defaultValue) => {
if (value === undefined || value === null || value === '') return defaultValue;
if (typeof value === 'boolean') return value;
return value === 'true' || value === '1';
};
export const config = { export const config = {
env: process.env.NODE_ENV || 'development', env: process.env.NODE_ENV || 'development',
port: parseNumber(process.env.PORT, 3001), port: parseNumber(process.env.PORT, 3001),
@@ -51,6 +57,7 @@ export const config = {
}, },
g5db: { g5db: {
enabled: !!process.env.POSTGRES_HOST_G5, enabled: !!process.env.POSTGRES_HOST_G5,
roomStatusMomentSyncEnabled: parseBoolean(process.env.G5_ROOM_STATUS_MOMENT_SYNC_ENABLED, false),
host: process.env.POSTGRES_HOST_G5, host: process.env.POSTGRES_HOST_G5,
port: parseNumber(process.env.POSTGRES_PORT_G5, 5434), port: parseNumber(process.env.POSTGRES_PORT_G5, 5434),
user: process.env.POSTGRES_USER_G5, user: process.env.POSTGRES_USER_G5,

View File

@@ -21,6 +21,10 @@ const bootstrap = async () => {
database: config.db.database, database: config.db.database,
schema: config.db.schema schema: config.db.schema
}, },
g5db: {
enabled: config.g5db.enabled,
roomStatusMomentSyncEnabled: config.g5db.roomStatusMomentSyncEnabled
},
kafka: { kafka: {
brokers: config.kafka.brokers, brokers: config.kafka.brokers,
topic: config.kafka.topic, topic: config.kafka.topic,
@@ -183,10 +187,12 @@ const bootstrap = async () => {
promises.push(g5DbManager.insertRows({ schema: config.g5db.schema, table: config.g5db.table, rows }).catch(e => { promises.push(g5DbManager.insertRows({ schema: config.g5db.schema, table: config.g5db.table, rows }).catch(e => {
logger.error('G5 Database insert failed but non-blocking', { error: e.message }); logger.error('G5 Database insert failed but non-blocking', { error: e.message });
})); }));
if (config.g5db.roomStatusMomentSyncEnabled) {
promises.push(g5DbManager.upsertRoomStatusMomentIp(rows).catch(e => { promises.push(g5DbManager.upsertRoomStatusMomentIp(rows).catch(e => {
logger.error('G5 room_status_moment_g5 upsert failed but non-blocking', { error: e.message }); logger.error('G5 room_status_moment_g5 upsert failed but non-blocking', { error: e.message });
})); }));
} }
}
await Promise.all(promises); await Promise.all(promises);
metricCollector.increment('db_insert_count', 1); metricCollector.increment('db_insert_count', 1);
@@ -216,10 +222,12 @@ const bootstrap = async () => {
promises.push(g5DbManager.insertRows({ schema: config.g5db.schema, table: config.g5db.table, rows }).catch(e => { promises.push(g5DbManager.insertRows({ schema: config.g5db.schema, table: config.g5db.table, rows }).catch(e => {
logger.error('G5 Database insert failed in insertOnce', { error: e.message }); logger.error('G5 Database insert failed in insertOnce', { error: e.message });
})); }));
if (config.g5db.roomStatusMomentSyncEnabled) {
promises.push(g5DbManager.upsertRoomStatusMomentIp(rows).catch(e => { promises.push(g5DbManager.upsertRoomStatusMomentIp(rows).catch(e => {
logger.error('G5 room_status_moment_g5 upsert failed in insertOnce', { error: e.message }); logger.error('G5 room_status_moment_g5 upsert failed in insertOnce', { error: e.message });
})); }));
} }
}
await Promise.all(promises); await Promise.all(promises);
metricCollector.increment('db_insert_count', 1); metricCollector.increment('db_insert_count', 1);
metricCollector.increment('db_insert_ms_sum', Date.now() - startedAt); metricCollector.increment('db_insert_ms_sum', Date.now() - startedAt);