Event emitter
In-process, fire-and-forget async on a later tick. No queue, no serialization, no resolveNotifiable — the simplest way to move delivery off the request without any infrastructure.
The event-emitter dispatcher moves delivery off the request path without adding any
infrastructure. No Redis, no worker — just @nestjs/event-emitter, which the core already
depends on for lifecycle events.
It's the simplest way to go async. dispatch() emits an internal event carrying the live job
and returns immediately, so the caller is never blocked on channel delivery. An async @OnEvent
handler then picks the job up on a later tick and runs the channels.
Install
pnpm add @dudousxd/nestjs-notifications-event-emitter @nestjs/event-emitternpm install @dudousxd/nestjs-notifications-event-emitter @nestjs/event-emitterWire it up
Pass EventEmitterDispatcher as the dispatcher. Make sure EventEmitterModule.forRoot() is
imported (it usually already is — the core uses it for events).
import { Module } from '@nestjs/common';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { NotificationsModule } from '@dudousxd/nestjs-notifications-core';
import { EventEmitterDispatcher } from '@dudousxd/nestjs-notifications-event-emitter';
@Module({
imports: [
EventEmitterModule.forRoot(),
NotificationsModule.forRoot({
dispatcher: EventEmitterDispatcher,
}),
],
})
export class AppModule {}That's the whole setup. forRoot registers the dispatcher as a provider, so its @OnEvent
handler is discovered and wired by @nestjs/event-emitter automatically.
Now any notification with shouldQueue = true is delivered on a later tick instead of inline.
No serialization, no rehydration
Because delivery stays in the same process, the live Notifiable and Notification
instances are passed straight through — nothing is serialized. That means:
- No
toNotifiableRef()on your notifiable. - No
notifications: [...]registry. - No
resolveNotifiableinforRoot.
You get fire-and-forget async with zero rehydration cost. Contrast this with the cross-process BullMQ and Redis dispatchers, which serialize the job — see Async dispatch.
Errors are surfaced via events
The work runs detached, so a throw inside a channel isn't returned to the caller. Failures are
isolated per channel and surfaced through the usual lifecycle events
(notification.failed) — subscribe to them to log or alert. See
Configuration → events.
Dispatchers
A dispatcher decides where and when a notification is processed — inline now, or on a worker later. The default is synchronous; opt into async per notification with shouldQueue and swap the driver in forRoot.
BullMQ
Out-of-process delivery on a BullMQ worker, reusing your app's existing @nestjs/bullmq and Redis connection. Jobs serialize, enqueue with retry and backoff, and rehydrate on the worker.