Event Bus
The Event Bus is the core mechanism in DomusJS for publishing and subscribing to domain events.
✅ Decouples event publishers from subscribers.
✅ Supports event-driven architectures and microservices.
✅ Allows adding middleware or integrating with external brokers like RabbitMQ or Google Pub/Sub.
What is the Event Bus?
Section titled “What is the Event Bus?”Without an event bus, you would need to manually call all listeners, making the system tightly coupled.
With the event bus:
- You publish domain events.
- The bus finds the registered handlers.
- Each handler processes the event.
Example:
await eventBus.publish([new UserRegisteredEvent(userId, email)]);
✅ The publisher does not need to know who handles the event.
Event Bus Setup
Section titled “Event Bus Setup”To use the Event Bus, you need to:
✅ Ensure the EventBus implementation has been initialized (by default, InMemoryEventBus
).
✅ Register each DomainEvent and its associated EventHandler.
ℹ️ Note:
TheEventBus
should have been initialized earlier by callingregisterDomusCore()
.
You can then safely resolve it from the container usingcontainer.resolve()
.
Example Use Case: User Registered Event
Section titled “Example Use Case: User Registered Event”Step 1: Define the Event
Section titled “Step 1: Define the Event”import { DomainEvent } from '@domusjs/core';
export class UserRegisteredEvent implements DomainEvent { static readonly TYPE = 'USER_REGISTERED'; readonly type = UserRegisteredEvent.TYPE; readonly occurredAt: Date = new Date();
constructor(public readonly userId: string, public readonly email: string) {}
static fromJSON(data: any): UserRegisteredEvent { return new UserRegisteredEvent(data.userId, data.email); }}
ℹ️ Why
fromJSON
?
When events are passed over external brokers (e.g., RabbitMQ), they are serialized as plain objects or JSON.
ThefromJSON
method allows reconstructing the event back into its class form when consuming it, so handlers can work with proper instances, not just raw data.
Step 2: Create the Event Handler
Section titled “Step 2: Create the Event Handler”import { EventHandler } from '@domusjs/core';import { UserRegisteredEvent } from './user-registered.event';
export class UserRegisteredEventHandler implements EventHandler<UserRegisteredEvent> { async handle(event: UserRegisteredEvent): Promise<void> { // Send welcome email, log activity, etc. }}
Step 3: Register and Publish
Section titled “Step 3: Register and Publish”import { container } from 'tsyringe';import { UserRegisteredEvent } from './events/user-registered.event';import { UserRegisteredEventHandler } from './handlers/user-registered-event.handler';
// Resolve the EventBus (already set up by registerDomusCore)const eventBus = container.resolve<EventBus>('EventBus');
// Register the handlereventBus.register(UserRegisteredEvent, container.resolve(UserRegisteredEventHandler));
// Publish the eventawait eventBus.publish([new UserRegisteredEvent('123', 'john@example.com')]);
✅ You can attach multiple handlers to the same event.
✅ Middleware and tracing can be added without modifying app logic.
✅ Use tsyringe
for dependency injection.
✅ Register all handlers once at application startup.
Core Interfaces
Section titled “Core Interfaces”DomusJS defines the following interfaces:
DomainEvent
Section titled “DomainEvent”export interface DomainEvent { readonly type: string; readonly occurredAt: Date;}
EventHandler
Section titled “EventHandler”export interface EventHandler<E extends DomainEvent> { handle(event: E): Promise<void>;}
EventBus
Section titled “EventBus”export interface EventBus { publish(events: DomainEvent[]): Promise<void>; register<E extends DomainEvent>(eventClass: { TYPE: string }, handler: EventHandler<E>): void;}
✅ You can build your own EventBus by following this interface.
Implement Your Own Event Bus
Section titled “Implement Your Own Event Bus”While DomusJS ships with InMemoryEventBus
, you can implement custom solutions.
Advanced: Broker-Based Event Bus
Section titled “Advanced: Broker-Based Event Bus”In distributed systems or microservice architectures, it’s common to publish and subscribe to domain events through a message broker rather than relying on in-memory event delivery.
DomusJS supports this by allowing you to plug in a custom EventBus implementation.
🚀 Built-in: RabbitMQEventBus
DomusJS already ships with a production-ready RabbitMQEventBus
that connects to a RabbitMQ broker and dispatches events asynchronously. It is ideal for systems that require:
- Eventual consistency across services
- Loose coupling between bounded contexts
- Guaranteed delivery and retries
🔧 Custom Broker: Google Pub/Sub, Kafka, NATS…
You can also implement your own EventBus using any broker of your choice—like Google Pub/Sub, Kafka, or NATS—as long as itimplements the EventBus
interface.