nestjs icon indicating copy to clipboard operation
nestjs copied to clipboard

Error: channel is not available

Open singhajit1616 opened this issue 3 years ago • 9 comments

I'm creating an API which will accept the message and then will publish it to the queue.

So i have initialized my app.module.ts

@Module({
  imports: [
     RabbitMQModule.forRootAsync(RabbitMQModule, {
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        uri: configService.get('RABBIT_MQ_URI')
      })
    }),
  ],
  controllers: [AppController],
  providers: [
    AppService
  ],
})
export class AppModule {}

And in the service imported the library AMQPService like this constructor(private readonly amqpConnection: AmqpConnection){}

So when, using the methods exposed like this this.amqpConnection.channel.assertExchange(exchange.name, exchange.type, exchange.options); and it throws Error: channel is not available.

When logged amqpConnection, recieved this object

AmqpConnection {
  messageSubject: Subject {
    closed: false,
    currentObservers: null,
    observers: [],
    isStopped: false,
    hasError: false,
    thrownError: null
  },
  logger: Logger { context: 'AmqpConnection', options: {} },
  initialized: Subject {
    closed: false,
    currentObservers: null,
    observers: [],
    isStopped: false,
    hasError: false,
    thrownError: null
  },
  _managedChannels: {},
  _channels: {},
  config: {
    prefetchCount: 10,
    defaultExchangeType: 'topic',
    defaultRpcErrorBehavior: 'REQUEUE',
    defaultSubscribeErrorBehavior: 'REQUEUE',
    exchanges: [],
    defaultRpcTimeout: 10000,
    connectionInitOptions: { wait: true, timeout: 5000, reject: true },
    connectionManagerOptions: {},
    registerHandlers: true,
    enableDirectReplyTo: true,
    channels: {},
    enableControllerDiscovery: false
  }
}

Expectations:

  • Should be able to assert an exchange.

singhajit1616 avatar Apr 16 '22 13:04 singhajit1616

Can you please share an example repo that demonstrates the issue so that it can be properly investigated?

WonderPanda avatar Apr 18 '22 13:04 WonderPanda

@WonderPanda here is the repo link https://github.com/singhajit1616/backend_nest_api

singhajit1616 avatar Apr 18 '22 14:04 singhajit1616

Where is the value for RABBIT_MQ_URI coming from in your setup?

WonderPanda avatar Apr 18 '22 15:04 WonderPanda

@WonderPanda getting these values from .env file. And have updated the repo. And I have noticed that AmqpConnection is creating a new instance as while creating the connection i have configured it something like this

RabbitMQModule.forRootAsync(RabbitMQModule, {
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        uri: configService.get('RABBIT_MQ_URI'),
        prefetchCount: 100,
        connectionInitOptions: { wait: false }
      })
    })

And the log is also showing the same config under the package

{
  prefetchCount: 100,
  defaultExchangeType: 'topic',
  defaultRpcErrorBehavior: 'REQUEUE',      
  defaultSubscribeErrorBehavior: 'REQUEUE',
  exchanges: [],
  defaultRpcTimeout: 10000,
  connectionInitOptions: { wait: false },  
  connectionManagerOptions: {},
  registerHandlers: true,
  enableDirectReplyTo: true,
  channels: {},
  enableControllerDiscovery: false,
  uri: 'amqp://guest:guest@localhost:5672'
}

But while accessing the connection through AmqpConnection the config object is different

{
  prefetchCount: 10,
  defaultExchangeType: 'topic',
  defaultRpcErrorBehavior: 'REQUEUE',
  defaultSubscribeErrorBehavior: 'REQUEUE',
  exchanges: [],
  defaultRpcTimeout: 10000,
  connectionInitOptions: { wait: true, timeout: 5000, reject: true },
  connectionManagerOptions: {},
  registerHandlers: true,
  enableDirectReplyTo: true,
  channels: {},
  enableControllerDiscovery: false
}

singhajit1616 avatar Apr 19 '22 04:04 singhajit1616

Hello, I have similar trouble.

This is my module

@Module({
  imports: [
    RabbitMQModule.forRootAsync(RabbitMQModule, {
      useFactory: createRabbitMqConfig,
      inject: [ConfigService],
    }),
  ],
  providers: [RabbitMqService],
  exports: [RabbitMqService],
})
export class RabbitModule {}

This is an config file that export an function with configuration file

import { RabbitMQConfig } from '@golevelup/nestjs-rabbitmq';
import { ConfigService } from '@nestjs/config';

export const createRabbitMqConfig = (configService: ConfigService) => {
  const config: RabbitMQConfig = {
    exchanges: [
      {
        name: 'amq.direct',
        type: 'direct',
      },
    ],
    channels: {
      'channel-1': {
        default: true,
      },
    },
    uri: configService.get<string>('RABBITMQ_CONNECTION_URL'),
    enableControllerDiscovery: true,
    connectionInitOptions: { wait: true },
  };
  return config;
};

This is my service file

import { AmqpConnection, RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';

@Injectable()
export class RabbitMqService implements OnModuleInit, OnModuleDestroy {
  constructor(private readonly amqpConnection: AmqpConnection) {}

  @RabbitSubscribe({
    exchange: 'amq.direct',
    routingKey: 'messages',
    queue: 'messages',
    queueOptions: {
      channel: 'channel-1',
    },
  })
  message(message) {
    console.log(message);
  }

  async publishMessage(message) {
    await this.amqpConnection.publish('amq.direct', 'messages', message);
  }

  onModuleDestroy() {
    console.log('RabbitMqService destroyed');
  }
  async onModuleInit() {
    console.log('RabbitMqService initialized');
  }
}

The basic problem is that the "amqpConnection" is not injected on service and due this is undefined

nitoba avatar Apr 24 '22 00:04 nitoba

I think this is bug of the version 2.3.0 In version "@golevelup/nestjs-rabbitmq": "2.2.0" all works fine

nitoba avatar Apr 24 '22 00:04 nitoba

I can attest downgrading to 2.2.0 works. We were refactoring our code from vanilla NestJS messaging to this library. We have a Web runtime that processes HTTP request and sends to fanout queues, and Worker runtime processing jobs. We got to a point where Web was downgraded and we forgot to downgrade Workers', and the Messaging Module is even a shared git between those two apps. Only the Worker 2.3.x version was receiving an undefined AmqpConnection. After also downgrading it, worker's running fine.

fmalk avatar May 26 '22 23:05 fmalk

@singhajit1616 @NitoBa @fmalk Try specifying default: true in your connection options. It looks like this may have been an unintentional breaking change in https://github.com/golevelup/nestjs/pull/411. If that fixes the issue, I can update the documentation and try to make the defaults make more sense!

andrewda avatar Jul 29 '22 06:07 andrewda

Since we're still using 2.2 for our backend, best if we tried to update it to current version and see if problem persist. However that's not a priority. When that happens, I'll report back here.

fmalk avatar Jul 29 '22 14:07 fmalk

Also getting this in the latest (3.4.0) and 3.3.0. 3.2.0 works as expected.

nerdyman avatar Jan 30 '23 17:01 nerdyman