Skip to content

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.


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.


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:
The EventBus should have been initialized earlier by calling registerDomusCore().
You can then safely resolve it from the container using container.resolve().

user-registered.event.ts
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.
The fromJSON method allows reconstructing the event back into its class form when consuming it, so handlers can work with proper instances, not just raw data.

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.
}
}
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 handler
eventBus.register(UserRegisteredEvent, container.resolve(UserRegisteredEventHandler));
// Publish the event
await 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.


DomusJS defines the following interfaces:

export interface DomainEvent {
readonly type: string;
readonly occurredAt: Date;
}
export interface EventHandler<E extends DomainEvent> {
handle(event: E): Promise<void>;
}
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.


While DomusJS ships with InMemoryEventBus, you can implement custom solutions.

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.