@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
text/typescript
/**
* 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 = [];
}
}