Recipes
Cluster-wide WebSocket broadcast
Every instance subscribes to the same channel; publishing from anywhere reaches the sockets connected to all instances.
typescript
import { Injectable } from '@nestjs/common';
import { Subscribe, IPubSubMessage } from '@nestjs-redisx/pubsub';
import { NotificationGateway } from './types';
/**
* Fan out server events to WebSocket clients on EVERY instance: each instance
* subscribes to the same channel, so a message published anywhere reaches all
* connected sockets cluster-wide.
*/
@Injectable()
export class RealtimeBridge {
constructor(private readonly gateway: NotificationGateway) {}
@Subscribe('broadcast.notifications')
onNotification(message: IPubSubMessage<{ userId: string; text: string }>): void {
this.gateway.broadcast(`notify:${message.data.userId}`, message.data);
}
}Cross-service domain events
Publish domain events from write paths and let any number of services react without coupling:
typescript
import { Injectable, Inject } from '@nestjs/common';
import { PUBSUB_SERVICE, IPubSubService } from '@nestjs-redisx/pubsub';
import { UserCreatedEvent } from './types';
@Injectable()
export class UserPublisher {
constructor(
@Inject(PUBSUB_SERVICE)
private readonly pubsub: IPubSubService,
) {}
async userCreated(user: UserCreatedEvent): Promise<void> {
// Payload is JSON-serialized; returns the number of subscribers reached.
const receivers = await this.pubsub.publish('user.created', user);
if (receivers === 0) {
// Pub/Sub is fire-and-forget: nobody was listening right now.
}
}
}Consumers subscribe by exact channel or by family via patterns:
typescript
import { Injectable } from '@nestjs/common';
import { Subscribe, IPubSubMessage } from '@nestjs-redisx/pubsub';
import { UserCreatedEvent, NotificationGateway } from './types';
@Injectable()
export class UserEventsHandler {
constructor(private readonly gateway: NotificationGateway) {}
// Auto-subscribed on startup via discovery.
@Subscribe('user.created')
onUserCreated(message: IPubSubMessage<UserCreatedEvent>): void {
this.gateway.broadcast('user:new', message.data);
}
// Redis glob patterns: *, ?, [..]
@Subscribe({ pattern: 'order.*' })
onAnyOrderEvent(message: IPubSubMessage): void {
// message.pattern === 'order.*', message.channel === concrete channel
this.gateway.broadcast(message.channel, message.data);
}
}Choosing between Pub/Sub and Streams
| Need | Use |
|---|---|
| Fire-and-forget fan-out, lowest latency | Pub/Sub |
| Guaranteed processing, replay, consumer groups | Streams |
| Both (notify now + process reliably) | Publish to a stream, Pub/Sub-notify consumers |