# ListenersController

**Kind:** Class

**Source:** [`packages/microservices/listeners-controller.ts`](https://github.com/nestjs/nest/blob/master/packages/microservices/listeners-controller.ts#L45)

**Part of:** [Microservices](subsystem-packages-microservices)

`ListenersController` is an internal NestJS microservices component that discovers `@MessagePattern()` and `@EventPattern()` handlers on controllers and registers them with a microservice server. It also resolves request-scoped handlers, attaches client proxies to decorated properties, and normalizes handler results into RxJS observables for transport processing.

## Methods

| Method | Signature | Returns |
|---|---|---|
| `registerPatternHandlers` | `registerPatternHandlers(instanceWrapper: InstanceWrapper<Controller>, serverInstance: Server, moduleKey: string)` | `void` |
| `insertEntrypointDefinition` | `insertEntrypointDefinition(instanceWrapper: InstanceWrapper, definition: EventOrMessageListenerDefinition, transportId: Transport | symbol)` | `void` |
| `forkJoinHandlersIfAttached` | `forkJoinHandlersIfAttached(currentReturnValue: Promise<unknown> | Observable<unknown>, originalArgs: unknown[], handlerRef: MessageHandler)` | `void` |
| `assignClientsToProperties` | `assignClientsToProperties(instance: Controller)` | `void` |
| `assignClientToInstance` | `assignClientToInstance(instance: Controller, property: string, client: T)` | `void` |
| `createRequestScopedHandler` | `createRequestScopedHandler(wrapper: InstanceWrapper, pattern: PatternMetadata, moduleRef: Module, moduleKey: string, methodKey: string, defaultCallMetadata: Record<string, any>, isEventHandler: undefined)` | `void` |
| `transformToObservable` | `transformToObservable(resultOrDeferred: Observable<T> | Promise<T>)` | `Observable<T>` |
| `transformToObservable` | `transformToObservable(resultOrDeferred: T)` | `never extends Observable<ObservedValueOf<T>> ? Observable<T> : Observable<ObservedValueOf<T>>` |
| `transformToObservable` | `transformToObservable(resultOrDeferred: any)` | `void` |

## Where it refuses work

- `ListenersController` stops the work with an early return when `isEventHandler`.
- `ListenersController` stops the work with an early return when `resultOrDeferred instanceof Promise`.
- `ListenersController` stops the work with an early return when `isObservable(resultOrDeferred)`.

## When something fails

- `ListenersController` handles failure in 1 place: it turns it into a return value in all 1.

## Diagram

```mermaid
graph LR
  A[Nest application bootstrap] --> B[ListenersController]
  B --> C[Discover controller methods]
  C --> D[Read message/event pattern metadata]
  D --> E[Register handlers on microservice server]
  E --> F[Request-scoped handler creation]
  E --> G[Observable response stream]
  B --> H[Assign @Client() proxies to properties]
  H --> I[Controller instances]
```

## Usage

```ts
import { Controller } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import {
  ClientProxy,
  ClientProxyFactory,
  MessagePattern,
  Transport,
} from '@nestjs/microservices';
import { AppModule } from './app.module';

@Controller()
class OrdersController {
  // In normal applications, ListenersController assigns this proxy
  // when using Nest's @Client() decorator and module metadata.
  private readonly billingClient: ClientProxy = ClientProxyFactory.create({
    transport: Transport.TCP,
  });

  @MessagePattern({ cmd: 'get-order' })
  getOrder(orderId: string) {
    return {
      id: orderId,
      status: 'confirmed',
    };
  }

  @MessagePattern({ cmd: 'stream-order-events' })
  streamOrderEvents() {
    return this.billingClient.send({ cmd: 'order-events' }, {});
  }
}

async function bootstrap() {
  const app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.TCP,
  });

  // During startup, Nest internally uses ListenersController to
  // discover and register @MessagePattern() handlers.
  await app.listen();
}

bootstrap();
```

## AI Coding Instructions

- Treat `ListenersController` as framework infrastructure; applications should register handlers through `@MessagePattern()` and `@EventPattern()` rather than instantiating this class directly.
- Preserve observable normalization when changing handler invocation logic: handlers may return plain values, promises, or RxJS observables.
- Keep request-scoped handlers isolated by using the request context and scoped provider resolution path rather than reusing singleton controller instances.
- When adding transport integrations, ensure every discovered pattern is registered with the server and that attached event handlers are joined/forked correctly.
- Maintain client-property assignment behavior for controller instances using Nest microservice client proxy metadata.

## Relationships

- IMPORTS → `Controller`
- IMPORTS → `isUndefined`
- IMPORTS → `ContextIdFactory`
- IMPORTS → `ExecutionContextHost`
- IMPORTS → `STATIC_CONTEXT`
- IMPORTS → `NestContainer`
- IMPORTS → `Injector`
- IMPORTS → `ContextId`
- IMPORTS → `InstanceWrapper`
- IMPORTS → `Module`
- IMPORTS → `GraphInspector`
- IMPORTS → `MetadataScanner`
- IMPORTS → `REQUEST_CONTEXT_ID`
