RabbitMQ — servislar orasida xabar almashish
Muammodan boshlaylik
Orders Service buyurtma yaratdi. Notifications Service ga email yuborishi kerak. Lekin ular alohida ilovalar — bir-birini to'g'ridan-to'g'ri chaqira olmaydi.
HTTP bilan to'g'ridan-to'g'ri chaqirish mumkin — lekin muammo bor:
Orders Service ──HTTP──► Notifications Service
↑ ishlamayapti!
Notifications Service vaqtincha ishlamasa — buyurtma ham yaratilmaydi. Ikkisi bir-biriga bog'liq bo'lib qoldi.
Yechim: Message Queue. Xabarni qoldiring — Notifications Service o'zi kelganda olsin.
RabbitMQ nima?
RabbitMQ — servislar orasida xabar almashish uchun navbat tizimi (message broker).
Bir servis xabar yozib navbatga tashlaydi — ikkinchi servis tayyor bo'lganda navbatdan oladi.
Hayotiy o'xshatma
Pochta qutisi. Siz xat yozib pochta qutisiga solasiz. Qabul qiluvchi uyda bo'lmasa ham — xat saqlanib qoladi. U qaytganda xatni oladi. Siz uni kutib o'tirmagansiz.
Orders ──► [pochta qutiси / RabbitMQ] ──► Notifications
xabar saqlanib turadi
RabbitMQ ni qanday ishga tushirish?
Eng sodda yo'l — CloudAMQP (bepul, o'rnatish shart emas):
- cloudamqp.com ga kiring
- "Create New Instance" → "Little Lemur" (bepul tarif)
- Dastur nomi va region tanlang
- "Details" da URL ni nusxalang — shunday ko'rinadi:
amqps://abcdef:XyZ123@moose.rmq.cloudamqp.com/abcdef
Shu URL — RabbitMQ serveringiz manzili. Docker yoki o'rnatish kerak emas.
O'rnatish
npm install @nestjs/microservices amqplib amqp-connection-manager
Loyiha tuzilmasi
Bu yerda ikkita alohida NestJS ilova ishlatamiz:
myapp/
orders-service/ ← buyurtmalar (xabar yuboradi)
src/
orders/
orders.module.ts
orders.service.ts
app.module.ts
main.ts
.env
notifications-service/ ← bildirishnomalar (xabar qabul qiladi)
src/
notifications/
notifications.controller.ts
notifications.module.ts
app.module.ts
main.ts
.env
.env fayllar
# orders-service/.env
RABBITMQ_URL=amqps://abcdef:XyZ123@moose.rmq.cloudamqp.com/abcdef
# notifications-service/.env
RABBITMQ_URL=amqps://abcdef:XyZ123@moose.rmq.cloudamqp.com/abcdef
Consumer — xabarlarni qabul qiluvchi
Notifications Service navbatni tinglaydi:
// notifications-service/src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.RMQ,
options: {
urls: [process.env.RABBITMQ_URL],
queue: 'notifications_queue', // ← shu navbatni tinglaydi
},
});
await app.listen();
console.log('Notifications service ishga tushdi');
}
bootstrap();
// notifications-service/src/notifications/notifications.controller.ts
import { Controller } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';
@Controller()
export class NotificationsController {
@EventPattern('order.created') // ← shu xabar kelganda ishlaydi
async handleOrderCreated(@Payload() data: { email: string; orderId: string }) {
console.log(`Email yuborilmoqda: ${data.email}`);
// shu yerda haqiqiy email yuborish
}
}
Producer — xabar yuboruvchi
Orders Service navbatga xabar qoldiradi:
// orders-service/src/orders/orders.module.ts
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { OrdersService } from './orders.service';
@Module({
imports: [
ClientsModule.register([
{
name: 'NOTIFICATIONS_SERVICE', // ← inject qilishda shu nom
transport: Transport.RMQ,
options: {
urls: [process.env.RABBITMQ_URL],
queue: 'notifications_queue', // ← consumer bilan bir xil bo'lishi shart
},
},
]),
],
providers: [OrdersService],
})
export class OrdersModule {}
// orders-service/src/orders/orders.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
@Injectable()
export class OrdersService {
constructor(
@Inject('NOTIFICATIONS_SERVICE') private notifyClient: ClientProxy,
) {}
async createOrder(dto: { email: string; product: string }) {
const order = { id: Date.now(), ...dto };
// Navbatga xabar qoldiramiz — javob kutmaymiz
this.notifyClient.emit('order.created', {
email: dto.email,
orderId: order.id,
});
return order; // ← darhol qaytadi, Notifications Service kutilmaydi
}
}
Nima uchun emit, nima uchun send?
// emit — bir tomonlama (pochta qutisi)
// Xabar yuborasiz, javob kutmaysiz
this.notifyClient.emit('order.created', data);
// send — ikki tomonlama (telefon)
// Javob kutiladi
const result = await firstValueFrom(
this.inventoryClient.send('check.stock', { productId: 1 })
);
Consumer da ham shunga mos:
// emit uchun — javob qaytarmaydi
@EventPattern('order.created')
handleOrder(@Payload() data: any) { ... }
// send uchun — javob qaytaradi
@MessagePattern('check.stock')
checkStock(@Payload() data: any) {
return { available: true }; // ← Orders Service ga qaytadi
}
Tez-tez uchraydigan xatolar
1. Xabar yetkazilmayapti
Sababi: Queue nomi producer va consumer da mos kelmayapti.
Yechim: Ikkala tomonda queue: 'notifications_queue' aynan bir xil bo'lsin.
2. send() javob bermayapti
Sababi: Consumer da @EventPattern ishlatilgan — u javob qaytarmaydi.
Yechim: Javob kerak bo'lsa @MessagePattern ishlating.
3. CloudAMQP ga ulanmayapti
Error: connect ECONNREFUSED
Sababi: URL noto'g'ri yoki .env fayl o'qilmayapti.
Yechim: console.log(process.env.RABBITMQ_URL) bilan URL ni tekshiring. ConfigModule orqali .env yuklanganini tasdiqlang.
Xulosa
- RabbitMQ — servislar orasida ishonchli xabar almashish
- CloudAMQP — o'rnatishsiz, bepul bulutdagi RabbitMQ
- Producer —
notifyClient.emit()bilan navbatga xabar qoldiradi - Consumer —
@EventPattern()bilan navbatni tinglaydi - Queue nomi ikki tomonda ham bir xil bo'lishi shart
emit— javobsiz,send— javobli
Keyingi dars: 41-dars: Microservices — HTTP orqali ma'lumot almashish