UNPKG

@logistically/events

Version:

A production-ready event-driven architecture library for NestJS with Redis Streams, comprehensive batching, reliable consumption, and enterprise-grade features.

100 lines (99 loc) 3.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BatchedEventConsumer = void 0; const consumer_1 = require("./consumer"); class BatchedEventConsumer { constructor(options) { this.batchHandlers = new Map(); this.activeBatches = 0; this.config = options; this.maxConcurrentBatches = options.maxConcurrentBatches || 5; // Create base consumer with batch handler this.baseConsumer = new consumer_1.EventConsumer({ ...options, handlers: { ...options.handlers, 'batch': this.handleBatch.bind(this), // Register batch handler }, }); } async handleBatch(body, header, raw) { if (this.activeBatches >= this.maxConcurrentBatches) { throw new Error('Too many concurrent batches being processed'); } this.activeBatches++; try { const batchEnvelope = raw; const messages = batchEnvelope.body.messages; if (this.config.processBatchInOrder !== false) { // Process messages in order await this.processBatchInOrder(messages); } else { // Process messages concurrently (use with caution) await this.processBatchConcurrently(messages); } } finally { this.activeBatches--; } } async processBatchInOrder(messages) { for (const message of messages) { try { await this.processIndividualMessage(message); } catch (error) { console.error(`Failed to process message ${message.originalId} in batch:`, error); // Continue processing other messages in the batch // Failed messages can be handled by the client code } } } async processBatchConcurrently(messages) { const promises = messages.map(async (message) => { try { await this.processIndividualMessage(message); } catch (error) { console.error(`Failed to process message ${message.originalId} in batch:`, error); // Continue processing other messages in the batch } }); await Promise.allSettled(promises); } async processIndividualMessage(message) { const handler = this.baseConsumer['handlers'][message.eventType]; if (!handler) { if (this.baseConsumer['logUnregisteredEvents'] !== 'none') { console[this.baseConsumer['logUnregisteredEvents']](`[BatchedEventConsumer] No handler registered for event type: ${message.eventType}, ignoring message`); } return; } // Use the original envelope that was created at operation time await handler(message.body, message.envelope.header, message.envelope); } // Expose base consumer methods async handleMessage(rawMessage) { // Check if this is a batch envelope if (rawMessage && rawMessage.header && rawMessage.header.type === 'batch') { // Handle as batch envelope const batchEnvelope = rawMessage; return this.handleBatch(batchEnvelope.body, batchEnvelope.header, batchEnvelope); } else { // Handle as regular event envelope return this.baseConsumer.handleMessage(rawMessage); } } get handlers() { return this.baseConsumer['handlers']; } get validator() { return this.baseConsumer['validator']; } get activeBatchCount() { return this.activeBatches; } } exports.BatchedEventConsumer = BatchedEventConsumer;