@logistically/events-nestjs
Version:
NestJS integration for @logistically/events v3 - Event-driven architecture with Redis Streams
165 lines (164 loc) • 7.46 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var PerformanceMonitorService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PerformanceMonitorService = void 0;
const common_1 = require("@nestjs/common");
const event_metadata_explorer_service_1 = require("./event-metadata-explorer.service");
const event_discovery_service_1 = require("./event-discovery.service");
let PerformanceMonitorService = PerformanceMonitorService_1 = class PerformanceMonitorService {
constructor(metadataExplorer, eventDiscoveryService) {
this.metadataExplorer = metadataExplorer;
this.eventDiscoveryService = eventDiscoveryService;
this.logger = new common_1.Logger(PerformanceMonitorService_1.name);
this.startTime = Date.now();
this.processingTimes = [];
this.lastDiscoveryRun = 0;
}
async onModuleInit() {
this.logger.log('PerformanceMonitorService initialized');
// Start periodic performance reporting
this.startPerformanceReporting();
}
/**
* Get comprehensive performance metrics
*/
getMetrics() {
const cacheStats = this.metadataExplorer.getCacheStats();
const discoveryStats = this.eventDiscoveryService.getDiscoveryStats();
const memoryUsage = process.memoryUsage();
const avgProcessingTime = this.processingTimes.length > 0
? this.processingTimes.reduce((a, b) => a + b, 0) / this.processingTimes.length
: 0;
return {
cache: {
hits: cacheStats.hits,
misses: cacheStats.misses,
hitRate: cacheStats.hitRate,
},
discovery: {
pending: discoveryStats.pending,
registered: discoveryStats.registered,
retryCount: discoveryStats.retryCount,
processingTime: avgProcessingTime,
},
memory: {
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024 * 100) / 100, // MB
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024 * 100) / 100, // MB
external: Math.round(memoryUsage.external / 1024 / 1024 * 100) / 100, // MB
},
timing: {
lastDiscoveryRun: this.lastDiscoveryRun,
averageProcessingTime: Math.round(avgProcessingTime * 100) / 100,
totalRuns: this.processingTimes.length,
},
};
}
/**
* Record processing time for performance tracking
*/
recordProcessingTime(processingTime) {
this.processingTimes.push(processingTime);
// Keep only last 100 measurements to prevent memory bloat
if (this.processingTimes.length > 100) {
this.processingTimes = this.processingTimes.slice(-100);
}
}
/**
* Record discovery run completion
*/
recordDiscoveryRun() {
this.lastDiscoveryRun = Date.now();
}
/**
* Get performance summary for logging
*/
getPerformanceSummary() {
const metrics = this.getMetrics();
const uptime = Math.round((Date.now() - this.startTime) / 1000);
return `Performance Summary (uptime: ${uptime}s):
Cache: ${metrics.cache.hitRate}% hit rate (${metrics.cache.hits}/${metrics.cache.hits + metrics.cache.misses})
Discovery: ${metrics.discovery.registered} registered, ${metrics.discovery.pending} pending
Memory: ${metrics.memory.heapUsed}MB used / ${metrics.memory.heapTotal}MB total
Processing: ${metrics.timing.averageProcessingTime}ms average (${metrics.timing.totalRuns} runs)`;
}
/**
* Start periodic performance reporting
*/
startPerformanceReporting() {
// Report performance every 5 minutes
setInterval(() => {
const summary = this.getPerformanceSummary();
this.logger.log(summary);
// Log warnings for potential performance issues
this.checkPerformanceWarnings();
}, 5 * 60 * 1000);
}
/**
* Check for performance warnings and log them
*/
checkPerformanceWarnings() {
const metrics = this.getMetrics();
// Cache hit rate warning
if (metrics.cache.hitRate < 50) {
this.logger.warn(`Low cache hit rate: ${metrics.cache.hitRate}%. Consider pre-warming cache for frequently accessed services.`);
}
// Memory usage warning
if (metrics.memory.heapUsed > metrics.memory.heapTotal * 0.8) {
this.logger.warn(`High memory usage: ${metrics.memory.heapUsed}MB / ${metrics.memory.heapTotal}MB. Consider monitoring for memory leaks.`);
}
// Processing time warning
if (metrics.discovery.processingTime > 1000) {
this.logger.warn(`Slow discovery processing: ${metrics.discovery.processingTime}ms average. Consider optimizing service registration.`);
}
// Retry count warning
if (metrics.discovery.retryCount > 10) {
this.logger.warn(`High retry count: ${metrics.discovery.retryCount}. Check for service registration issues.`);
}
}
/**
* Reset performance metrics (useful for testing)
*/
resetMetrics() {
this.processingTimes = [];
this.lastDiscoveryRun = 0;
this.logger.log('Performance metrics reset');
}
/**
* Get performance recommendations based on current metrics
*/
getRecommendations() {
const metrics = this.getMetrics();
const recommendations = [];
if (metrics.cache.hitRate < 50) {
recommendations.push('Consider pre-warming cache for frequently accessed services');
}
if (metrics.discovery.processingTime > 1000) {
recommendations.push('Consider optimizing service registration with batching');
}
if (metrics.discovery.retryCount > 10) {
recommendations.push('Investigate service registration failures and retry logic');
}
if (metrics.memory.heapUsed > metrics.memory.heapTotal * 0.8) {
recommendations.push('Monitor memory usage and consider implementing memory cleanup');
}
if (recommendations.length === 0) {
recommendations.push('Performance is within acceptable ranges');
}
return recommendations;
}
};
exports.PerformanceMonitorService = PerformanceMonitorService;
exports.PerformanceMonitorService = PerformanceMonitorService = PerformanceMonitorService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [event_metadata_explorer_service_1.EventMetadataExplorer,
event_discovery_service_1.EventDiscoveryService])
], PerformanceMonitorService);