UNPKG

@sailboat-computer/event-bus

Version:

Standardized event bus for sailboat computer v3 with resilience features and offline capabilities

268 lines (228 loc) 6.05 kB
/** * Metrics collector for event bus */ import { EventBusMetrics } from '@sailboat-computer/sailboat-types'; /** * Extended event bus metrics */ export interface ExtendedEventBusMetrics extends EventBusMetrics { /** * Average event processing time in milliseconds */ averageProcessingTime: number; /** * Processing time samples */ processingTimeSamples: number[]; /** * Number of events in the dead letter queue */ deadLetterQueueSize: number; /** * Number of events sent to the dead letter queue */ deadLetterQueueEvents: number; /** * Last time an event was sent to the dead letter queue */ lastDeadLetterQueueEventTime: Date | null; } /** * Metrics collector for event bus */ export class MetricsCollector { /** * Number of published events */ private publishedEvents: number = 0; /** * Number of failed publishes */ private failedPublishes: number = 0; /** * Number of processed events */ private processedEvents: number = 0; /** * Number of active subscriptions */ private activeSubscriptions: number = 0; /** * Number of reconnection attempts */ private reconnectionAttempts: number = 0; /** * Number of events in the offline buffer */ private bufferedEvents: number = 0; /** * Last reconnection time */ private lastReconnectionTime: Date | null = null; /** * Total processing time */ private totalProcessingTime: number = 0; /** * Number of events in the dead letter queue */ private deadLetterQueueSize: number = 0; /** * Number of events sent to the dead letter queue */ private deadLetterQueueEvents: number = 0; /** * Last time an event was sent to the dead letter queue */ private lastDeadLetterQueueEventTime: Date | null = null; /** * Whether to collect detailed timings */ private detailedTimings: boolean; /** * Processing times array for calculating average */ private processingTimes: number[] = []; /** * Maximum number of processing times to store */ private maxProcessingTimes: number = 100; /** * Create a new metrics collector * * @param detailedTimings - Whether to collect detailed timings */ constructor(detailedTimings: boolean = false) { this.detailedTimings = detailedTimings; } /** * Increment the published events counter */ incrementPublishedEvents(): void { this.publishedEvents++; } /** * Increment the failed publishes counter */ incrementFailedPublishes(): void { this.failedPublishes++; } /** * Increment the processed events counter */ incrementProcessedEvents(): void { this.processedEvents++; } /** * Increment the active subscriptions counter */ incrementActiveSubscriptions(): void { this.activeSubscriptions++; } /** * Decrement the active subscriptions counter */ decrementActiveSubscriptions(): void { if (this.activeSubscriptions > 0) { this.activeSubscriptions--; } } /** * Set the active subscriptions count * * @param count - Active subscriptions count */ setActiveSubscriptions(count: number): void { this.activeSubscriptions = count; } /** * Increment the reconnection attempts counter */ incrementReconnectionAttempts(): void { this.reconnectionAttempts++; this.lastReconnectionTime = new Date(); } /** * Set the buffered events count * * @param count - Buffered events count */ setBufferedEvents(count: number): void { this.bufferedEvents = count; } /** * Set the dead letter queue size * * @param size - Dead letter queue size */ setDeadLetterQueueSize(size: number): void { this.deadLetterQueueSize = size; } /** * Increment the dead letter queue events counter */ incrementDeadLetterQueueEvents(): void { this.deadLetterQueueEvents++; this.lastDeadLetterQueueEventTime = new Date(); } /** * Record event processing time * * @param startTime - Start time in milliseconds */ recordProcessingTime(startTime: number): void { if (!this.detailedTimings) { return; } const processingTime = Date.now() - startTime; // Add to processing times array this.processingTimes.push(processingTime); // Limit the array size if (this.processingTimes.length > this.maxProcessingTimes) { this.processingTimes.shift(); } // Calculate average const sum = this.processingTimes.reduce((a: number, b: number) => a + b, 0); const averageProcessingTime = sum / this.processingTimes.length; // Update total processing time this.totalProcessingTime = averageProcessingTime; } /** * Get metrics * * @returns Event bus metrics */ getMetrics(): ExtendedEventBusMetrics { return { publishedEvents: this.publishedEvents, failedPublishes: this.failedPublishes, processedEvents: this.processedEvents, activeSubscriptions: this.activeSubscriptions, reconnectionAttempts: this.reconnectionAttempts, bufferedEvents: this.bufferedEvents, lastReconnectionTime: this.lastReconnectionTime, averageProcessingTime: this.totalProcessingTime, processingTimeSamples: [...this.processingTimes], deadLetterQueueSize: this.deadLetterQueueSize, deadLetterQueueEvents: this.deadLetterQueueEvents, lastDeadLetterQueueEventTime: this.lastDeadLetterQueueEventTime }; } /** * Reset metrics */ reset(): void { this.publishedEvents = 0; this.failedPublishes = 0; this.processedEvents = 0; this.activeSubscriptions = 0; this.reconnectionAttempts = 0; this.bufferedEvents = 0; this.lastReconnectionTime = null; this.totalProcessingTime = 0; this.deadLetterQueueSize = 0; this.deadLetterQueueEvents = 0; this.lastDeadLetterQueueEventTime = null; this.processingTimes = []; } }