@ideal-photography/shared
Version:
Shared MongoDB and utility logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, audit logs, minimart items/orders, and push notification subscriptions.
62 lines (57 loc) • 2.13 kB
JavaScript
import EventEmitter from 'events';
/**
* Central AlertBus for emitting and listening to system alert events.
*
* Internally maintains a micro-queue so that heavy alert handlers
* never block the caller thread. All alert payloads are processed
* asynchronously in FIFO order.
*/
class AlertBus extends EventEmitter {
constructor() {
super();
// Simple in-memory queue (FIFO)
this.queue = [];
this.isProcessing = false;
}
/**
* Emit an alert trigger. Consumers should subscribe to the
* `alert` event or listen for specific triggers via
* `bus.on(triggerName, handler)`.
*
* @param {string} trigger Canonical event name e.g. `user.registered`
* @param {any} payload Arbitrary payload data for handlers
* @param {object} opts Optional meta e.g. channel overrides
*/
enqueue(trigger, payload = {}, opts = {}) {
this.queue.push({ trigger, payload, opts });
this._schedule();
}
/**
* Schedule queue processing on next tick if not already scheduled.
* Ensures only one processing loop runs at a time.
* @private
*/
_schedule() {
if (this.isProcessing) return;
this.isProcessing = true;
// Process asynchronously so caller returns immediately
setImmediate(async () => {
try {
while (this.queue.length) {
const job = this.queue.shift();
// Wildcard event for global listeners
this.emit('alert', job);
// Specific trigger event e.g. `user.registered`
this.emit(job.trigger, job.payload, job.opts);
}
} finally {
this.isProcessing = false;
// If new jobs were enqueued while processing, schedule again
if (this.queue.length) this._schedule();
}
});
}
}
// Export a singleton instance so the bus is shared process-wide
const bus = new AlertBus();
export default bus;