@sailboat-computer/event-bus
Version:
Standardized event bus for sailboat computer v3 with resilience features and offline capabilities
230 lines • 7.19 kB
JavaScript
"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