@golevelup/nestjs-rabbitmq启动多实例报3000端口占用问题
端口占用问题根因
3000端口占用和@golevelup/nestjs-rabbitmq包无关,该包仅会通过AMQP协议连接RabbitMQ服务的5672端口,不会监听HTTP端口。
报错的核心原因是NestJS应用默认启动HTTP服务时会监听3000端口,你启动第一个消费者实例时已经占用了3000端口,第二个实例沿用默认配置启动HTTP服务时,就会触发端口占用错误。
解决方法
根据你的消费者服务是否需要提供HTTP接口,二选一即可:
- 保留HTTP服务,为不同实例分配不同端口
修改启动入口main.ts,支持从环境变量读取监听端口,启动不同实例时传入不同端口值即可:
启动第一个实例用默认配置即可,启动第二个实例时执行// main.ts import { NestFactory } from '@nestjs/core'; import { EventsModule } from './events.module'; async function bootstrap() { const app = await NestFactory.create(EventsModule); // 优先读取环境变量中的端口配置,无配置时 fallback 到3000 await app.listen(process.env.PORT ? Number(process.env.PORT) : 3000); } bootstrap();PORT=3001 npm run start(Windows系统用set PORT=3001 && npm run start),就不会出现端口冲突。 - 纯消息消费场景,直接关闭HTTP服务
如果你的消费者服务不需要对外提供HTTP接口,完全可以不启动HTTP监听,从根源上避免端口占用问题:
这种方式启动任意多个消费者实例,都不会产生HTTP端口冲突。// main.ts 纯消费场景配置 import { NestFactory } from '@nestjs/core'; import { EventsModule } from './events.module'; async function bootstrap() { // 用应用上下文模式启动,不初始化HTTP服务 const app = await NestFactory.createApplicationContext(EventsModule); await app.init(); } bootstrap();
Pub/Sub模式配置注意事项
你当前的代码配置无法实现发布订阅广播效果,需要调整几个点:
- 交换机配置不匹配:
RabbitMQModule.forRoot中仅声明了amq.topic类型的交换机,但@RabbitSubscribe装饰器中配置的是amq.direct交换机,需要统一交换机名称、类型,否则会触发交换机不存在的报错。 - 队列配置不符合广播逻辑:RabbitMQ默认会将同一个队列的消息轮询分发给绑定的消费者,如果你希望一条消息被所有订阅的消费者实例接收,不能给所有消费者配置同一个固定队列名
queueNameToBeConsumed,需要给每个消费者实例生成独立的临时队列:@RabbitSubscribe({ exchange: 'amq.topic', // 和全局配置的交换机保持一致 routingKey: 'book-created', // 和发布端的路由键匹配 queue: '', // 传空字符串会自动生成随机独占队列 queueOptions: { exclusive: true, // 连接断开时自动删除该临时队列 }, errorHandler: (channel: Channel, msg: ConsumeMessage, error: Error) => { console.log(error); channel.reject(msg, false); }, }) - 发布端路由不匹配:你当前使用NestJS内置的RMQ客户端是直接往固定队列发消息,不会走交换机广播逻辑,建议统一使用
@golevelup/nestjs-rabbitmq提供的amqpConnection.publish()方法往对应交换机发消息,保证路由规则符合pub/sub预期。
内容的提问来源于stack exchange,提问作者Khai Dao
相关产品推荐
相关产品推荐

