Event Emitter

~15 daq · NestJS · Ilg'or mavzular

Muammodan boshlaylik

Foydalanuvchi ro'yxatdan o'tdi. Siz qilishingiz kerak:

  1. Xush kelibsiz email yuboring
  2. Analytics ga yozib qo'ying
  3. Admin ga xabar bering

Buni hammasini UsersService ichida yozish mumkin:

async register(dto: RegisterDto) {
  const user = await this.create(dto);
  await this.emailService.sendWelcome(user);
  await this.analyticsService.track(user);
  await this.notificationService.notifyAdmin(user);
  return user;
}

Muammo: UsersService 3 ta boshqa servicega bog'liq. Har yangi talabda shu faylni o'zgartirish kerak. Modullar bir-biriga chirmashib ketdi.

Yechim — UsersService faqat "foydalanuvchi yaratildi" degan signal yuborsin, qolganlar o'zlari eshitsin.


Event Emitter nima?

Event Emitter — bitta joy event chiqaradi, boshqalar eshitadi. Chiqaruvchi va eshituvchi bir-birini bilmaydi.


Hayotiy o'xshatma

Radio stantsiya. Stantsiya kimga eshitayotganini bilmaydi — u faqat signal uzatadi. Eshitgisi kelganlar o'z radiopriyomnikini ulab qo'yadi.

UsersService     Event Bus     EmailService
     │               │              │
     │─ user.created ►│              │
     │               │─ user.created ►│
     │               │              │ sendWelcome()

O'rnatish

npm install @nestjs/event-emitter
// app.module.ts
import { EventEmitterModule } from '@nestjs/event-emitter';

@Module({
  imports: [
    EventEmitterModule.forRoot(),
  ],
})
export class AppModule {}

Fayl tuzilmasi

src/
  users/
    users.service.ts    ← event chiqaradi
    users.module.ts
  email/
    email.service.ts    ← event eshitadi
    email.module.ts

Event yuborish

// users/users.service.ts
import { EventEmitter2 } from '@nestjs/event-emitter';

@Injectable()
export class UsersService {
  constructor(private eventEmitter: EventEmitter2) {}

  async create(dto: CreateUserDto) {
    const user = await this.userRepository.save(dto);

    this.eventEmitter.emit('user.created', user); // ← signal chiqarildi

    return user;
    // UsersService email, analytics ni bilmaydi — bu uning ishi emas
  }
}

Event eshitish (Listener)

// email/email.service.ts
import { OnEvent } from '@nestjs/event-emitter';

@Injectable()
export class EmailService {

  @OnEvent('user.created') // ← shu signalni eshitadi
  async handleUserCreated(user: User) {
    await this.sendWelcomeEmail(user.email);
  }
}
// analytics/analytics.service.ts
@Injectable()
export class AnalyticsService {

  @OnEvent('user.created') // ← bir event — bir necha listener bo'lishi mumkin
  async handleUserCreated(user: User) {
    await this.track('new_registration', user.id);
  }
}

Har ikkisi ham user.created ni eshitadi. UsersService ularni bilmaydi va bilmasligi kerak.


Async listener

// Default da listener sinxron ishlaydi.
// Async amallar uchun { async: true } qo'shing:

@OnEvent('user.created', { async: true })
async handleUserCreated(user: User) {
  await this.sendEmail(user.email); // ← await ishlaydi
}

Qachon Event Emitter ishlatish kerak?

Mos Mos emas
Email, log, analytics (side-effect) Asosiy biznes logika
Bir event — bir necha listener Natija kerak bo'lsa (return)
Modullar orasida loosely coupled So'rov-javob pattern

Tez-tez uchraydigan xatolar

1. Listener ishlamayapti Sababi: Listener joylashgan service o'z modulining providers ga qo'shilmagan. Yechim: EmailModule providers da EmailService borligini tekshiring.


2. Async listener kutilmayapti Sababi: { async: true } qo'yilmagan. Yechim: @OnEvent('user.created', { async: true }) — async amallar uchun kerak.


Xulosa

  • Event Emitter — modullar orasida loosely coupled aloqa
  • eventEmitter.emit('event.name', data) — event yuborish
  • @OnEvent('event.name') — event eshitish
  • UsersService email/analytics ni bilmaydi — faqat signal chiqaradi
  • Side-effectlar uchun ideal (email, log, notification)

Keyingi dars: 45-dars: Scheduled Tasks — Cron Jobs