Channel

πŸ“‘ Channels

In the @nestjstools/messaging library, Channels represent the underlying transport mechanisms that deliver messages between microservices. Each channel is responsible for handling message transmission, reception, serialization, and routing to the appropriate handlers.

Channels abstract the communication details, allowing your application to work seamlessly whether using in-memory queues, RabbitMQ, or any other supported transport.


πŸ” What Is a Channel?

A Channel is a pluggable component that:

  • Sends and receives messages over a specific transport protocol

  • Applies serialization and deserialization (normalizers)

  • Manages queues, exchanges, topics, or other infrastructure details

  • Supports middleware to process messages in the pipeline


πŸ›  Defining a Channel

Channels are configured within the MessagingModule via channel config classes. Each channel requires:

  • A unique name

  • Channel-specific options (connection info, queues, bindings)

  • Optional middlewares and normalizers

Example: InMemory Channel

import { InMemoryChannelConfig } from '@nestjstools/messaging';

new InMemoryChannelConfig({
  name: 'my-channel',
  middlewares: [LoggingMiddleware],
});

Example: AMQP Channel

import { MessagingRabbitmqExtensionModule, RmqChannelConfig, ExchangeType } from '@nestjstools/messaging-rabbitmq-extension';

new RmqChannelConfig({
  name: 'amqp-command',
  connectionUri: 'amqp://guest:guest@localhost:5672/',
  exchangeName: 'my_app_command.exchange',
  bindingKeys: ['my_app.command.#'],
  exchangeType: ExchangeType.TOPIC,
  queue: 'my_app.command',
  autoCreate: true,
  enableConsumer: true,
});

🧩 Channel Configuration Options

Option
Description

name

Unique identifier of the channel

middlewares

List of middleware classes to apply on messages

normalizer

Serializer/deserializer to encode/decode messages

Transport-specific options

Connection strings, queues, exchange names, binding keys, etc.

enableConsumer

Enables or disables the RabbitMQ consumer for this channel


πŸ”„ Channels and Buses

A Bus is connected to one or more channels. When a message is dispatched to a bus, it is forwarded to all its associated channels.

This design allows you to:

  • Send messages to multiple transports simultaneously

  • Mix different messaging protocols within the same application

  • Configure channels independently for flexibility and scaling


🧩 Middleware and Normalizers on Channels

Each channel can have its own middleware stack and normalizers, enabling per-transport processing and custom encoding/decoding.


πŸ“¦ Hook: onChannelDestroy

The onChannelDestroy The method is a lifecycle hook that is called when a channel instance is being destroyed. This is the appropriate place to clean up resources, close connections, or perform any teardown logic associated with your custom channel.

Purpose

Use onChannelDestroy to:

  • Gracefully close external connections (e.g., sockets, database clients, message queues).

  • Dispose of timers, intervals, or event listeners.

  • Free up resources tied to the channel’s lifecycle.

export class ExampleChannel extends Channel<ExampleChannelConfig> {
  constructor(config: ExampleChannelConfig) {
    super(config);
  }

  async onChannelDestroy(): Promise<void> {
    // Clean up logic here
    // For example, close an SQS client connection
    if (this.client) {
      await this.client.close();
    }
  }
}

Notes

  • The method should return a Promise<void>.

  • This hook is automatically called by the framework when the channel is being shut down.

  • Always handle errors gracefully to avoid issues during shutdown.


Benefits of Using Channels

Feature
Benefit

πŸ”Œ Transport Abstraction

Switch between RabbitMQ, in-memory, or other protocols easily

βš™οΈ Flexible Configuration

Fine-tune transport settings independently per channel

🧩 Extensible Middleware

Add custom logic like logging, auth, or metrics per channel

πŸ”„ Multi-Channel Support

Dispatch messages across multiple transports simultaneously

Last updated