rwadurian/backend/services/presence-service/src/infrastructure/metrics/metrics-collector.service.ts

78 lines
2.5 KiB
TypeScript

import { Injectable, Logger, Inject } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { MetricsService } from './metrics.service';
import { PresenceRedisRepository } from '../redis/presence-redis.repository';
import {
DAILY_ACTIVE_STATS_REPOSITORY,
IDailyActiveStatsRepository,
} from '../../domain/repositories/daily-active-stats.repository.interface';
import {
EVENT_LOG_REPOSITORY,
IEventLogRepository,
} from '../../domain/repositories/event-log.repository.interface';
import { format } from 'date-fns';
@Injectable()
export class MetricsCollectorService {
private readonly logger = new Logger(MetricsCollectorService.name);
private readonly presenceWindowSeconds: number;
constructor(
private readonly metricsService: MetricsService,
private readonly presenceRedisRepository: PresenceRedisRepository,
@Inject(DAILY_ACTIVE_STATS_REPOSITORY)
private readonly dauRepository: IDailyActiveStatsRepository,
@Inject(EVENT_LOG_REPOSITORY)
private readonly eventLogRepository: IEventLogRepository,
) {
this.presenceWindowSeconds = parseInt(
process.env.PRESENCE_WINDOW_SECONDS || '180',
10,
);
}
/**
* 每 15 秒更新在线人数指标
*/
@Cron('*/15 * * * * *')
async collectOnlineUsersMetric(): Promise<void> {
try {
const now = Math.floor(Date.now() / 1000);
const threshold = now - this.presenceWindowSeconds;
const count = await this.presenceRedisRepository.countOnlineUsers(threshold);
this.metricsService.setOnlineUsers(count);
this.logger.debug(`Online users metric updated: ${count}`);
} catch (error) {
this.logger.error('Failed to collect online users metric', error);
}
}
/**
* 每 5 分钟更新 DAU 指标
*/
@Cron(CronExpression.EVERY_5_MINUTES)
async collectDauMetric(): Promise<void> {
try {
const today = new Date();
const dateStr = format(today, 'yyyy-MM-dd');
const stats = await this.dauRepository.findByDate(today);
if (stats) {
this.metricsService.setDau(dateStr, stats.dauCount);
this.logger.debug(`DAU metric updated: ${dateStr} = ${stats.dauCount}`);
}
} catch (error) {
this.logger.error('Failed to collect DAU metric', error);
}
}
/**
* 启动时立即收集一次
*/
async onModuleInit(): Promise<void> {
await this.collectOnlineUsersMetric();
await this.collectDauMetric();
}
}