- 将主键从自增id改为GUID格式并添加格式校验 - 为service_mask添加表达式索引优化首位查询性能 - 更新相关文档说明改造方案与验证步骤 - 添加统计模块记录数据库写入与Kafka消费量 - 重构Redis心跳协议改用LIST类型存储项目状态 - 修复部署脚本中的服务名称不一致问题
125 lines
4.2 KiB
JavaScript
125 lines
4.2 KiB
JavaScript
// 项目入口文件
|
||
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';
|
||
import { StatsCounters, StatsReporter } from './stats/statsManager.js';
|
||
|
||
class WebBLSHeartbeatServer {
|
||
constructor() {
|
||
this.config = config;
|
||
this.kafkaConsumer = null;
|
||
this.heartbeatProcessor = null;
|
||
this.databaseManager = null;
|
||
this.redis = null;
|
||
this.consumers = null;
|
||
this.stats = new StatsCounters();
|
||
this.statsReporter = null;
|
||
}
|
||
|
||
async start() {
|
||
try {
|
||
// 初始化 Redis(按协议写入心跳与控制台日志)
|
||
this.redis = new RedisIntegration(this.config.redis);
|
||
await this.redis.connect();
|
||
this.redis.startHeartbeat();
|
||
this.statsReporter = new StatsReporter({ redis: this.redis, stats: this.stats });
|
||
this.statsReporter.start();
|
||
|
||
// 初始化数据库连接
|
||
this.databaseManager = new DatabaseManager({ ...this.config.db, maxConnections: 1 });
|
||
await this.databaseManager.connect();
|
||
console.log('数据库连接成功');
|
||
await this.redis?.info('数据库连接成功', { module: 'db' });
|
||
|
||
// 打印 Kafka 配置摘要,便于排查连接问题
|
||
console.log('正在初始化 Kafka 消费者...');
|
||
console.log('Kafka 配置:', {
|
||
brokers: this.config.kafka?.brokers,
|
||
topics: this.config.kafka?.topics,
|
||
groupId: this.config.kafka?.groupId,
|
||
fromOffset: this.config.kafka?.fromOffset ?? 'latest',
|
||
ssl: !!this.config.kafka?.sslEnabled,
|
||
sasl: this.config.kafka?.saslEnabled ? `enabled (mechanism: ${this.config.kafka?.saslMechanism})` : 'disabled'
|
||
});
|
||
|
||
// 初始化处理器(共享批处理队列)
|
||
this.heartbeatProcessor = new HeartbeatProcessor(this.config.processor, this.databaseManager, {
|
||
redis: this.redis,
|
||
stats: this.stats,
|
||
});
|
||
|
||
// 在单进程内启动 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.statsReporter) {
|
||
this.statsReporter.stop();
|
||
this.statsReporter = null;
|
||
}
|
||
|
||
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) {
|
||
console.error('停止失败:', error);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 启动服务器
|
||
const server = new WebBLSHeartbeatServer();
|
||
server.start();
|
||
|
||
// 处理进程终止信号
|
||
process.on('SIGINT', () => {
|
||
server.stop();
|
||
process.exit(0);
|
||
});
|
||
|
||
process.on('SIGTERM', () => {
|
||
server.stop();
|
||
process.exit(0);
|
||
});
|
||
|
||
export { WebBLSHeartbeatServer };
|