feat: 实现Redis集成与Kafka消息处理优化

- 新增Redis集成模块,支持心跳写入与控制台日志队列
- 优化Kafka消费者实现,支持多实例与自动重连
- 改进消息处理器,支持批量处理与多层解码
- 更新数据库表结构,调整字段类型与约束
- 添加Redis与Kafka的配置项和环境变量支持
- 补充测试用例和文档说明
This commit is contained in:
2026-01-14 17:58:45 +08:00
parent eb94aaf92b
commit 910f1c353f
28 changed files with 1691 additions and 177 deletions

View File

@@ -3,6 +3,7 @@ import config from './config/config.js';
import { KafkaConsumer } from './kafka/consumer.js';
import { HeartbeatProcessor } from './processor/heartbeatProcessor.js';
import { DatabaseManager } from './db/databaseManager.js';
import { RedisIntegration } from './redis/redisIntegration.js';
class WebBLSHeartbeatServer {
constructor() {
@@ -10,48 +11,69 @@ class WebBLSHeartbeatServer {
this.kafkaConsumer = null;
this.heartbeatProcessor = null;
this.databaseManager = null;
this.redis = null;
this.consumers = null;
}
async start() {
try {
// 初始化 Redis按协议写入心跳与控制台日志
this.redis = new RedisIntegration(this.config.redis);
await this.redis.connect();
this.redis.startHeartbeat();
// 初始化数据库连接
this.databaseManager = new DatabaseManager(this.config.db);
this.databaseManager = new DatabaseManager({ ...this.config.db, maxConnections: 1 });
await this.databaseManager.connect();
console.log('数据库连接成功');
await this.redis?.info('数据库连接成功', { module: 'db' });
// 初始化处理器
this.heartbeatProcessor = new HeartbeatProcessor(
this.config.processor,
this.databaseManager
);
// 初始化处理器(共享批处理队列)
this.heartbeatProcessor = new HeartbeatProcessor(this.config.processor, this.databaseManager);
// 初始化Kafka消费者
this.kafkaConsumer = new KafkaConsumer(
this.config.kafka,
this.heartbeatProcessor.processMessage.bind(this.heartbeatProcessor)
);
await this.kafkaConsumer.connect();
await this.kafkaConsumer.subscribe();
await this.kafkaConsumer.startConsuming();
console.log('Kafka消费者启动成功');
// 在单进程内启动 N 个消费者实例(与分区数匹配)
const instances = Math.max(1, Number(this.config.kafka?.consumerInstances ?? 1));
this.consumers = [];
for (let i = 0; i < instances; i++) {
const consumer = new KafkaConsumer(
{ ...this.config.kafka, consumerInstanceIndex: i },
this.heartbeatProcessor.processMessage.bind(this.heartbeatProcessor)
);
await consumer.connect();
await consumer.subscribe();
await consumer.startConsuming();
this.consumers.push({ consumer });
}
console.log(`Kafka消费者启动成功${instances} 个实例`);
await this.redis?.info('Kafka消费者启动成功', { module: 'kafka', topic: this.config.kafka?.topic, instances });
console.log('BLS心跳接收端启动成功');
await this.redis?.info('BLS心跳接收端启动成功', { module: 'app' });
} catch (error) {
console.error('启动失败:', error);
await this.redis?.error('启动失败', { module: 'app', error: String(error?.message ?? error) });
process.exit(1);
}
}
async stop() {
try {
if (this.kafkaConsumer) {
await this.kafkaConsumer.stopConsuming();
await this.kafkaConsumer.disconnect();
if (this.consumers && Array.isArray(this.consumers)) {
for (const { consumer } of this.consumers) {
await consumer.stopConsuming();
await consumer.disconnect();
}
this.consumers = null;
}
if (this.databaseManager) {
await this.databaseManager.disconnect();
}
if (this.redis) {
await this.redis.info('BLS心跳接收端已停止', { module: 'app' });
await this.redis.disconnect();
}
console.log('BLS心跳接收端已停止');
} catch (error) {
@@ -75,4 +97,4 @@ process.on('SIGTERM', () => {
process.exit(0);
});
export { WebBLSHeartbeatServer };
export { WebBLSHeartbeatServer };