UNPKG

@logistically/events

Version:

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

95 lines (94 loc) 3.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedisStreamsBatchingStrategy = void 0; const crypto_1 = require("crypto"); class RedisStreamsBatchingStrategy { constructor(typePrefix, batchingTypeStrategy = 'exact') { this.typePrefix = typePrefix; this.batchingTypeStrategy = batchingTypeStrategy; } canBatchTogether(message1, message2) { // Only batch messages with the same batching key const key1 = this.getBatchingKey(message1.eventType); const key2 = this.getBatchingKey(message2.eventType); return key1 === key2; } createBatchEnvelope(messages) { const batchId = (0, crypto_1.createHash)('sha256') .update(`${Date.now()}-${Math.random()}`) .digest('hex'); return { header: { type: `${this.typePrefix}batch`, messageCount: messages.length, batchId, timestamp: new Date().toISOString(), }, body: { messages, }, }; } async sendBatch(transport, batchEnvelope) { const stream = this.getBatchStreamName(); if (typeof transport.dispatchEvent === 'function') { await transport.dispatchEvent({ pattern: batchEnvelope.header.type, data: batchEnvelope }, { stream }); } else { await transport.emit(batchEnvelope.header.type, batchEnvelope); } } async sendIndividualMessages(basePublisher, messages) { const results = await Promise.allSettled(messages.map(async (message) => { try { const { transport, prefix } = basePublisher['getTransportForEvent'](message.eventType); const finalEventType = prefix ? `${prefix}${message.eventType}` : message.eventType; const stream = this.getStreamForEventType(message.eventType); if (typeof transport.dispatchEvent === 'function') { await transport.dispatchEvent({ pattern: finalEventType, data: message.envelope }, { stream }); } else { await transport.emit(finalEventType, message.envelope); } } catch (error) { console.error(`Failed to send individual message ${message.originalId}:`, error); throw error; } })); // Check if any messages failed const failedResults = results.filter(result => result.status === 'rejected'); if (failedResults.length > 0) { throw new Error(`${failedResults.length} individual messages failed to send`); } } getBatchStreamName() { return `${this.typePrefix}events`; } getBatchingKey(eventType) { if (this.batchingTypeStrategy === 'exact') { return eventType; } const parts = eventType.split('.'); if (typeof this.batchingTypeStrategy === 'number') { const position = this.batchingTypeStrategy; if (position >= parts.length) { // If position is beyond the available parts, use the full event type return eventType; } // Join parts up to the specified position return parts.slice(0, position + 1).join('.'); } // Default to exact matching return eventType; } getEventTypePrefix(eventType) { const parts = eventType.split('.'); return parts.length > 1 ? `${parts[0]}.` : 'default.'; } getStreamForEventType(eventType) { const prefix = this.getEventTypePrefix(eventType); return `${prefix}events`; } } exports.RedisStreamsBatchingStrategy = RedisStreamsBatchingStrategy;