UNPKG

@sailboat-computer/event-bus

Version:

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

230 lines 7.19 kB
"use strict"; /** * Dead letter queue implementation */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createDeadLetterQueueManager = exports.DeadLetterQueueManager = void 0; const uuid_1 = require("uuid"); const utils_1 = require("./utils"); /** * Dead letter queue manager */ class DeadLetterQueueManager { /** * Create a new dead letter queue manager * * @param maxSize - Maximum number of events to store in the dead letter queue * @param maxAttempts - Maximum number of processing attempts before sending to dead letter queue */ constructor(maxSize = 1000, maxAttempts = 3) { /** * Dead letter queue events */ this.events = new Map(); /** * Number of events sent to the dead letter queue */ this.totalEvents = 0; /** * Last time an event was sent to the dead letter queue */ this.lastEventTime = null; this.maxSize = maxSize; this.maxAttempts = maxAttempts; } /** * Add an event to the dead letter queue * * @param event - Event envelope * @param error - Error that caused the event to be sent to the dead letter queue * @param attempts - Number of processing attempts * @returns Event ID */ addEvent(event, error, attempts) { // Generate a new ID for the dead letter event const eventId = (0, uuid_1.v4)(); // Create dead letter event const deadLetterEvent = { eventType: event.type, data: event.data, originalEventId: event.id, timestamp: new Date(), attempts, error: { message: error.message, ...(error.stack ? { stack: error.stack } : {}), ...((error.code !== undefined) ? { code: error.code } : {}) } }; // Add event to the queue this.events.set(eventId, deadLetterEvent); // Update metrics this.totalEvents++; this.lastEventTime = deadLetterEvent.timestamp; // Prune if necessary if (this.events.size > this.maxSize) { this.pruneOldestEvent(); } utils_1.logger.warn(`Event ${event.id} of type ${event.type} sent to dead letter queue after ${attempts} attempts: ${error.message}`); return eventId; } /** * Get events from the dead letter queue * * @param eventType - Optional event type to filter by * @param limit - Maximum number of events to return * @returns Dead letter queue events */ getEvents(eventType, limit) { // Convert map to array let events = Array.from(this.events.entries()).map(([id, event]) => ({ ...event, id })); // Filter by event type if specified if (eventType) { events = events.filter(event => event.eventType === eventType); } // Sort by timestamp (newest first) events.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); // Limit if specified if (limit && limit > 0) { events = events.slice(0, limit); } return events; } /** * Get an event from the dead letter queue * * @param eventId - Event ID * @returns Dead letter event or null if not found */ getEvent(eventId) { return this.events.get(eventId) || null; } /** * Remove an event from the dead letter queue * * @param eventId - Event ID * @returns True if the event was removed, false if it wasn't found */ removeEvent(eventId) { return this.events.delete(eventId); } /** * Clear the dead letter queue * * @param eventType - Optional event type to filter by * @returns Number of events removed */ clearEvents(eventType) { if (!eventType) { // Clear all events const count = this.events.size; this.events.clear(); return count; } // Clear events of a specific type let count = 0; for (const [id, event] of this.events.entries()) { if (event.eventType === eventType) { this.events.delete(id); count++; } } return count; } /** * Get the number of events in the dead letter queue * * @returns Number of events */ getSize() { return this.events.size; } /** * Get the total number of events sent to the dead letter queue * * @returns Total number of events */ getTotalEvents() { return this.totalEvents; } /** * Get the last time an event was sent to the dead letter queue * * @returns Last event time or null if no events have been sent */ getLastEventTime() { return this.lastEventTime; } /** * Get the maximum number of processing attempts before sending to dead letter queue * * @returns Maximum number of attempts */ getMaxAttempts() { return this.maxAttempts; } /** * Set the maximum number of processing attempts before sending to dead letter queue * * @param maxAttempts - Maximum number of attempts */ setMaxAttempts(maxAttempts) { this.maxAttempts = maxAttempts; } /** * Get the maximum number of events to store in the dead letter queue * * @returns Maximum number of events */ getMaxSize() { return this.maxSize; } /** * Set the maximum number of events to store in the dead letter queue * * @param maxSize - Maximum number of events */ setMaxSize(maxSize) { this.maxSize = maxSize; // Prune if necessary while (this.events.size > this.maxSize) { this.pruneOldestEvent(); } } /** * Prune the oldest event from the dead letter queue */ pruneOldestEvent() { // Find the oldest event let oldestId = null; let oldestTime = Date.now(); for (const [id, event] of this.events.entries()) { const eventTime = event.timestamp.getTime(); if (eventTime < oldestTime) { oldestId = id; oldestTime = eventTime; } } // Remove the oldest event if (oldestId) { this.events.delete(oldestId); utils_1.logger.debug(`Pruned oldest event ${oldestId} from dead letter queue`); } } } exports.DeadLetterQueueManager = DeadLetterQueueManager; /** * Create a new dead letter queue manager * * @param maxSize - Maximum number of events to store in the dead letter queue * @param maxAttempts - Maximum number of processing attempts before sending to dead letter queue * @returns Dead letter queue manager */ function createDeadLetterQueueManager(maxSize, maxAttempts) { return new DeadLetterQueueManager(maxSize, maxAttempts); } exports.createDeadLetterQueueManager = createDeadLetterQueueManager; //# sourceMappingURL=dead-letter-queue.js.map