UNPKG

@medusajs/event-bus-local

Version:

Local Event Bus Module for Medusa

101 lines 4.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("@medusajs/framework/utils"); const events_1 = require("events"); const promises_1 = require("timers/promises"); const eventEmitter = new events_1.EventEmitter(); eventEmitter.setMaxListeners(Infinity); // eslint-disable-next-line max-len class LocalEventBusService extends utils_1.AbstractEventBusModuleService { constructor({ logger }, moduleOptions = {}, moduleDeclaration) { // @ts-ignore // eslint-disable-next-line prefer-rest-params super(...arguments); this.logger_ = logger; this.eventEmitter_ = eventEmitter; this.groupedEventsMap_ = new Map(); } /** * Accept an event name and some options * * @param eventsData * @param options The options can include `internal` which will prevent the event from being logged */ async emit(eventsData, options = {}) { const normalizedEventsData = Array.isArray(eventsData) ? eventsData : [eventsData]; for (const eventData of normalizedEventsData) { const eventListenersCount = this.eventEmitter_.listenerCount(eventData.name); if (eventListenersCount === 0) { continue; } if (!options.internal && !eventData.options?.internal) { this.logger_?.info(`Processing ${eventData.name} which has ${eventListenersCount} subscribers`); } await this.groupOrEmitEvent({ ...eventData, options, }); } } // If the data of the event consists of a eventGroupId, we don't emit the event, instead // we add them to a queue grouped by the eventGroupId and release them when // explicitly requested. // This is useful in the event of a distributed transaction where you'd want to emit // events only once the transaction ends. async groupOrEmitEvent(eventData) { const eventData_ = JSON.parse(JSON.stringify(eventData)); const { options, ...eventBody } = eventData_; const eventGroupId = eventBody.metadata?.eventGroupId; if (eventGroupId) { await this.groupEvent(eventGroupId, eventData_); } else { const { options, ...eventBody } = eventData_; const options_ = options; const delay = (ms) => (ms ? (0, promises_1.setTimeout)(ms) : Promise.resolve()); delay(options_?.delay).then(() => this.eventEmitter_.emit(eventData.name, eventBody)); } } // Groups an event to a queue to be emitted upon explicit release async groupEvent(eventGroupId, eventData) { const groupedEvents = this.groupedEventsMap_.get(eventGroupId) || []; groupedEvents.push(eventData); this.groupedEventsMap_.set(eventGroupId, groupedEvents); } async releaseGroupedEvents(eventGroupId) { let groupedEvents = this.groupedEventsMap_.get(eventGroupId) || []; groupedEvents = JSON.parse(JSON.stringify(groupedEvents)); for (const event of groupedEvents) { const { options, ...eventBody } = event; const options_ = options; const delay = (ms) => (ms ? (0, promises_1.setTimeout)(ms) : Promise.resolve()); delay(options_?.delay).then(() => this.eventEmitter_.emit(event.name, eventBody)); } await this.clearGroupedEvents(eventGroupId); } async clearGroupedEvents(eventGroupId) { this.groupedEventsMap_.delete(eventGroupId); } subscribe(event, subscriber, context) { super.subscribe(event, subscriber, context); this.eventEmitter_.on(event, async (data) => { try { await subscriber(data); } catch (err) { this.logger_?.error(`An error occurred while processing ${event.toString()}:`); this.logger_?.error(err); } }); return this; } unsubscribe(event, subscriber, context) { super.unsubscribe(event, subscriber, context); this.eventEmitter_.off(event, subscriber); return this; } } exports.default = LocalEventBusService; //# sourceMappingURL=event-bus-local.js.map