@sailboat-computer/event-bus
Version:
Standardized event bus for sailboat computer v3 with resilience features and offline capabilities
241 lines (204 loc) • 6.92 kB
text/typescript
/**
* Dead letter queue example
*
* This example demonstrates how to use the dead letter queue with the event bus.
*/
import { createEventBus, EventPriority, EventCategory } from '../src';
// Define the event type
interface SensorReadingEvent {
sensorId: string;
value: number;
unit: string;
timestamp: string;
}
// Define a schema for the sensor reading event
const sensorReadingSchema = {
type: 'object',
properties: {
sensorId: { type: 'string' },
value: { type: 'number' },
unit: { type: 'string' },
timestamp: { type: 'string', format: 'date-time' }
},
required: ['sensorId', 'value', 'unit', 'timestamp'],
additionalProperties: false
};
// Create a handler that will fail for certain sensor readings
function createFailingHandler(failureCondition: (event: SensorReadingEvent) => boolean) {
return (event: any) => {
const sensorReading = event.data as SensorReadingEvent;
console.log(`Processing sensor reading: ${sensorReading.sensorId} = ${sensorReading.value} ${sensorReading.unit}`);
// Simulate a failure for certain sensor readings
if (failureCondition(sensorReading)) {
throw new Error(`Failed to process sensor reading: ${sensorReading.sensorId}`);
}
console.log(`Successfully processed sensor reading: ${sensorReading.sensorId}`);
};
}
async function runExample() {
console.log('Starting dead letter queue example...');
// Create event bus with dead letter queue enabled
const eventBus = createEventBus({
adapter: {
type: 'memory',
config: {
serviceName: 'dlq-example'
}
},
offlineBuffer: {
maxSize: 100,
priorityRetention: true
},
metrics: {
enabled: true,
detailedTimings: true
},
deadLetterQueue: {
enabled: true,
maxSize: 100,
maxAttempts: 3
}
});
// Initialize event bus
await eventBus.initialize({
adapter: {
type: 'memory',
config: {
serviceName: 'dlq-example'
}
},
offlineBuffer: {
maxSize: 100,
priorityRetention: true
},
metrics: {
enabled: true,
detailedTimings: true
},
deadLetterQueue: {
enabled: true,
maxSize: 100,
maxAttempts: 3
}
});
// Register schema for sensor reading events
eventBus.registerSchema<SensorReadingEvent>('sensor.reading.v1', sensorReadingSchema);
console.log('Registered schema for sensor.reading.v1 event');
// Subscribe to sensor reading events with a handler that will fail for readings with value > 100
await eventBus.subscribe<SensorReadingEvent>(
'sensor.reading.v1',
createFailingHandler(reading => reading.value > 100)
);
console.log('Subscribed to sensor.reading.v1 events');
// Publish some sensor readings
const readings = [
{
sensorId: 'temp-cabin-main',
value: 22.5,
unit: '°C',
timestamp: new Date().toISOString()
},
{
sensorId: 'pressure-engine',
value: 120.0, // This will fail
unit: 'psi',
timestamp: new Date().toISOString()
},
{
sensorId: 'humidity-cabin',
value: 65.0,
unit: '%',
timestamp: new Date().toISOString()
},
{
sensorId: 'temp-engine',
value: 150.0, // This will fail
unit: '°C',
timestamp: new Date().toISOString()
}
];
// Publish each reading
for (const reading of readings) {
try {
console.log(`Publishing sensor reading: ${reading.sensorId} = ${reading.value} ${reading.unit}`);
await eventBus.publish<SensorReadingEvent>(
'sensor.reading.v1',
reading,
{
priority: EventPriority.NORMAL,
category: EventCategory.DATA,
tags: ['sensor', reading.sensorId]
}
);
console.log(`Published sensor reading: ${reading.sensorId}`);
} catch (error) {
console.error(`Failed to publish sensor reading: ${error.message}`);
}
// Wait a bit between events
await new Promise(resolve => setTimeout(resolve, 100));
}
// Wait for events to be processed
await new Promise(resolve => setTimeout(resolve, 1000));
// Get events from the dead letter queue
console.log('\nEvents in dead letter queue:');
const deadLetterEvents = await eventBus.getDeadLetterEvents();
if (deadLetterEvents.length === 0) {
console.log('No events in dead letter queue');
} else {
for (const event of deadLetterEvents) {
console.log(`- ${event.eventType}: ${JSON.stringify(event.data)}`);
console.log(` Error: ${event.error.message}`);
console.log(` Attempts: ${event.attempts}`);
console.log(` Timestamp: ${event.timestamp}`);
}
}
// Get metrics
const metrics = eventBus.getMetrics();
console.log('\nEvent Bus Metrics:');
console.log(`- Published events: ${metrics.publishedEvents}`);
console.log(`- Failed publishes: ${metrics.failedPublishes}`);
console.log(`- Processed events: ${metrics.processedEvents}`);
console.log(`- Dead letter queue size: ${(metrics as any).deadLetterQueueSize}`);
console.log(`- Dead letter queue events: ${(metrics as any).deadLetterQueueEvents}`);
// Republish an event from the dead letter queue with a modified value
if (deadLetterEvents.length > 0) {
const eventToRepublish = deadLetterEvents[0];
const eventId = (eventToRepublish as any).id;
console.log(`\nRepublishing event ${eventId} with modified value...`);
// Modify the event data to avoid the failure condition
const modifiedData = {
...eventToRepublish.data,
value: 90.0 // Lower the value to avoid the failure condition
};
// Republish the event
const newEventId = await eventBus.publish<SensorReadingEvent>(
eventToRepublish.eventType,
modifiedData,
{
priority: EventPriority.HIGH,
category: EventCategory.DATA,
tags: ['republished', 'modified']
}
);
console.log(`Republished event with new ID: ${newEventId}`);
// Remove the event from the dead letter queue
await eventBus.removeDeadLetterEvent(eventId);
console.log(`Removed event ${eventId} from dead letter queue`);
// Wait for the event to be processed
await new Promise(resolve => setTimeout(resolve, 500));
}
// Clear the dead letter queue
console.log('\nClearing dead letter queue...');
await eventBus.clearDeadLetterQueue();
// Verify the dead letter queue is empty
const remainingEvents = await eventBus.getDeadLetterEvents();
console.log(`Dead letter queue size after clearing: ${remainingEvents.length}`);
// Close the event bus
await eventBus.close();
console.log('\nDead letter queue example completed');
}
// Run the example
runExample().catch(error => {
console.error('Example failed:', error);
process.exit(1);
});