NestJS Kafka emit(), ์–ด๋””๊นŒ์ง€ ์„ฑ๊ณตํ–ˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์„๊นŒ?

๐Ÿ“š
Backend
2025.12.20

๐Ÿ“š Overview

ํ˜„์žฌ ์žฌ์ง ์ค‘์ธ ํšŒ์‚ฌ์—์„œ๋Š” SNS ๋งˆ์ผ€ํŒ…์„ ํ•˜๋‚˜์˜ ์ƒํ’ˆ์œผ๋กœ ๋งŒ๋“ค์–ด ํŒ๋งคํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์šด์˜ํ•˜๊ณ  ์žˆ๋‹ค.

๊ธฐ์—…์ด๋‚˜ ๊ฐœ์ธ ์‚ฌ์šฉ์ž๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ, ๋ธ”๋กœ๊ทธ, ์œ ํŠœ๋ธŒ ๋“ฑ ๋‹ค์–‘ํ•œ SNS ์ฑ„๋„์„ ๋Œ€์ƒ์œผ๋กœ ์ข‹์•„์š”, ํŒ”๋กœ์›Œ, ์กฐํšŒ์ˆ˜์™€ ๊ฐ™์€ ๋งˆ์ผ€ํŒ… ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ•  ์ˆ˜ ์žˆ๊ณ  ์„œ๋น„์Šค๋Š” ์ด ์ฃผ๋ฌธ์„ ์‹ค์ œ SNS ๋งˆ์ผ€ํŒ… ์ž‘์—…์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

์ด ๊ณผ์ •์€ ๋‹จ์ˆœํžˆ โ€œ์ฃผ๋ฌธ์„ ํ•˜๋‚˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒโ€์—์„œ ๋๋‚˜์ง€ ์•Š๋Š”๋‹ค.

  • ์ฃผ๋ฌธ ์ƒ์„ฑ
  • ๊ฒฐ์ œ ๋ฐ ํฌ์ธํŠธ ์ฐจ๊ฐ
  • ์ฃผ๋ฌธ ์ƒํƒœ ๊ด€๋ฆฌ
  • SNS ๋งˆ์ผ€ํŒ… ์ž‘์—… ์ง‘ํ–‰
  • ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ์™ธ๋ถ€ ๋งˆ์ผ€ํŒ… ์†”๋ฃจ์…˜ ์—…์ฒด์™€์˜ ์—ฐ๋™

๊นŒ์ง€ ์ด์–ด์ง€๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ ์ฒ˜๋ฆฌ ํ๋ฆ„์ด ์กด์žฌํ•œ๋‹ค.

ํŠนํžˆ, SNS ๋งˆ์ผ€ํŒ… ์ž‘์—…์€ ์ž์‚ฌ์—์„œ ์šด์˜ํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋„ ํ•˜๊ณ , ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ๋Š” ์™ธ๋ถ€ SNS ๋งˆ์ผ€ํŒ… ํ”Œ๋žซํผ(๊ณต๊ธ‰์ž) ์— ์ฃผ๋ฌธ์„ ์ „๋‹ฌํ•ด ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

์ด์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ ์ฃผ๋ฌธ์ด ์—ฌ๋Ÿฌ ์„œ๋ฒ„, ๋•Œ๋กœ๋Š” ์™ธ๋ถ€ ์‹œ์Šคํ…œ๊นŒ์ง€ ๊ฑฐ์ณ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค ์ „๋ฐ˜์€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜(MSA) ํ˜•ํƒœ๋ฅผ ๋ ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ตฌ์กฐ์—์„œ ์ฃผ๋ฌธ ์„œ๋น„์Šค์™€ SNS ์ฒ˜๋ฆฌ ์ฃผ์ฒด(์ž์‚ฌ ์„œ๋ฒ„ ํ˜น์€ ์™ธ๋ถ€ ๊ณต๊ธ‰์ž)๋ฅผ ๋А์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋น„์Šค์—์„œ๋Š” Kafka๋ฅผ ์‚ฌ์šฉํ•ด ๋ฉ”์‹œ์ง€ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฃผ๋ฌธ์„ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค.



1. Kafka ๋ฉ”์‹œ์ง€ ์ „์†ก์€ ์–ธ์ œ โ€œ์„ฑ๊ณตโ€์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์„๊นŒ?


Kafka๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ๋‹ค๊ณ  ํ•˜๋ฉด, ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํƒœ๋ฅผ ๊ธฐ๋Œ€ํ•œ๋‹ค.

  • ๋ฉ”์‹œ์ง€๊ฐ€ ๋ธŒ๋กœ์ปค์— ์ •์ƒ์ ์œผ๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.
  • ์ปจ์Šˆ๋จธ๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค.
  • ์ „์†ก ์ค‘ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด ํ˜ธ์ถœํ•œ ์ชฝ์—์„œ ์—๋Ÿฌ๋ฅผ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์‹ค์ œ Kafka ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ๋Š” โ€œ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ๋‹คโ€๋Š” ํ‘œํ˜„์ด ์ƒ๊ฐ๋ณด๋‹ค ํ›จ์”ฌ ๋ชจํ˜ธํ•˜๋‹ค. ๋ฉ”์‹œ์ง€๋ฅผ ์–ด๋””๊นŒ์ง€ ์ „๋‹ฌํ–ˆ์„ ๋•Œ๋ฅผ ์„ฑ๊ณต์œผ๋กœ ๋ณผ ๊ฒƒ์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ๋ˆ„๊ฐ€, ์–ธ์ œ ์•Œ ์ˆ˜ ์žˆ๋Š”์ง€๊ฐ€ ์ฝ”๋“œ๋งŒ ๋ด์„œ๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

NestJS์—์„œ Kafka ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœํ–‰ํ•  ๋•Œ, ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

@Injectable()
export class SendKafkaService {
  constructor(@Inject(KafkaService) private readonly client: ClientKafka) {}

  execute({ topic, data }: TopicProducerMessage): void {
    this.client.emit(topic, data);
  }
}

์ด ์ฝ”๋“œ๋Š” ๊ณผ์—ฐ ์–ด๋””๊นŒ์ง€ ์„ฑ๊ณตํ•œ ์ƒํƒœ์ผ๊นŒ?

  • Kafka ๋ธŒ๋กœ์ปค์— ์‹ค์ œ๋กœ ๋„๋‹ฌํ–ˆ์„๊นŒ?
  • ์ „์†ก์— ์‹คํŒจํ–ˆ๋‹ค๋ฉด ์—๋Ÿฌ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์„๊นŒ?
  • ์ด ์‹œ์ ์— ์ฃผ๋ฌธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ๋ ๊นŒ?

์ด ์งˆ๋ฌธ์— ๋‹ตํ•˜๋ ค๋ฉด, ๋จผ์ € NestJS์˜ emit()์ด ๋ฌด์—‡์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€๋ถ€ํ„ฐ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค.

Kafka ์ด์ „์—, ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฃจ๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ์‚ฌ์‹ค Kafka ์ด๋ฒคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ Observable ๊ฐ์ฒด์ด๋‹ค.

Observable ์ด๋ž€?

NestJS์˜ client.emit()์€ ๊ฐ’์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  Observable ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. Observable์€ ๊ฐ„๋‹จํžˆ ๋งํ•ด ์•„์ง ์‹คํ–‰๋˜์ง€ ์•Š์€ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ์— ๊ฐ€๊น๋‹ค. Observable์ด ๊ตฌ๋…(subscribe) ๋˜๊ฑฐ๋‚˜, firstValueFrom, lastValueFrom ๋“ฑ์œผ๋กœ await ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•œ ์„ฑ๊ณต์ด๋‚˜ ์‹คํŒจ๊ฐ€ ํ˜ธ์ถœํ•œ ์ชฝ์œผ๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š๋Š”๋‹ค.



2. emit()์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ์„๊นŒ?


์•ž์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ, emit()์„ ํ˜ธ์ถœํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ๊ณง๋ฐ”๋กœ โ€œKafka๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ๋‹คโ€๊ณ  ๋งํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค. ๊ทธ ์ด์œ ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด NestJS์˜ emit()์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ•œ ๋‹จ๊ณ„๋งŒ ๋” ๋“ค์–ด๊ฐ€ ๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

NestJS์—์„œ client.emit()์€ ๋‹จ์ˆœํžˆ โ€œKafka๋กœ ๋ฉ”์‹œ์ง€ ํ•˜๋‚˜ ๋‚ ๋ฆฌ๋Š” ํ•จ์ˆ˜โ€๊ฐ€ ์•„๋‹ˆ๋ผ, ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๊ณผ์ •์„ RxJS Observable๋กœ ๊ฐ์‹ผ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.

๋จผ์ € Nest์˜ ClientProxy.emit() ์ฃผ์„์—” ์ด๋ ‡๊ฒŒ ์ •์˜๋˜์–ด ์žˆ๋‹ค.

// @nestjs/microservices
/**
 * Emits an event to the server/broker.
 * Used for event-driven communication style between microservices.
 * @param pattern Pattern to identify the event
 * @param data Data to be sent
 * @returns Observable that completes when the event is successfully emitted
 */
emit<TResult = any, TInput = any>(pattern: any, data: TInput): Observable<TResult>;

์ฆ‰, emit()์€ โ€œ๊ฐ’์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜โ€ํ•˜๋Š” API๊ฐ€ ์•„๋‹ˆ๋ผ, ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์™„๋ฃŒ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” Observable ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.



3. ๊ทธ๋Ÿผ โ€œemit ์„ฑ๊ณตโ€์€ ์–ด๋””๊นŒ์ง€๋ฅผ ์˜๋ฏธํ• ๊นŒ?


emit()์€ Kafka๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ•˜๊ธฐ ์œ„ํ•œ API๋‹ค. ํ•˜์ง€๋งŒ emit()์„ ํ˜ธ์ถœํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ๊ทธ ์ฆ‰์‹œ โ€œ์ด๋ฒคํŠธ๊ฐ€ ๋ธŒ๋กœ์ปค์— ๋„์ฐฉํ–ˆ๋‹คโ€๊ณ  ๋งํ•  ์ˆ˜๋Š” ์—†๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ฐจ์ด๋Š” emit()์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃจ๋А๋ƒ์— ์žˆ๋‹ค.

this.client.emit(topic, payload);

์œ„์™€ ๊ฐ™์ด emit()์„ ๋‹จ์ˆœํžˆ ํ˜ธ์ถœ๋งŒ ํ•œ ๊ฒฝ์šฐ, ์ด ์ฝ”๋“œ๋Š” โ€œ์ด๋ฒคํŠธ ๋ฐœํ–‰์„ ์‹œ๋„ํ–ˆ๋‹คโ€ ์˜๋ฏธ์— ๊ฐ€๊น๋‹ค. ์ „์†ก ๊ณผ์ •์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ๊ทธ ์‹คํŒจ๋Š” Observable ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌ๋˜๋ฉฐ ํ˜ธ์ถœํ•œ ์ชฝ์—์„œ๋Š” ์ด๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ์˜๋ฏธ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.

import { lastValueFrom } from 'rxjs';

await lastValueFrom(this.client.emit(topic, payload));

emit()์ด ๋ฐ˜ํ™˜ํ•˜๋Š” Observable์€ ํ•œ ๋ฒˆ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฉ์ถœํ•˜๊ณ  complete ๋˜๋Š” ๋‹จ๋ฐœ ์ŠคํŠธ๋ฆผ์ด๊ธฐ ๋•Œ๋ฌธ์—, firstValueFrom ๋˜๋Š” lastValueFrom์„ ์‚ฌ์šฉํ•ด ์ „์†ก ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋‹ค.

  • emit()๋งŒ ํ˜ธ์ถœํ•œ ๊ฒฝ์šฐ โ†’ โ€œ์ด๋ฒคํŠธ๋ฅผ ๋ฐœํ–‰ํ–ˆ๋‹คโ€
  • emit()์ด ๋ฐ˜ํ™˜ํ•œ Observable ๊ฐ์ฒด๋ฅผ ๊ตฌ๋…ํ•œ ๊ฒฝ์šฐ โ†’ โ€œ์ด๋ฒคํŠธ๊ฐ€ ๋ธŒ๋กœ์ปค๊นŒ์ง€์˜ ์ „์†ก์ด ์—๋Ÿฌ ์—†์ด ์™„๋ฃŒ๋˜์—ˆ๋‹คโ€

๋ผ๊ณ  ์ดํ•ดํ•˜๋Š” ํŽธ์ด ํ›จ์”ฌ ์ •ํ™•ํ•˜๋‹ค.



4. emit ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์–ธ์ œ์ผ๊นŒ?


๊ทธ๋ ‡๋‹ค๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋Ÿฐ ์งˆ๋ฌธ์ด ์ƒ๊ธด๋‹ค.

  • ๊ทธ๋ ‡๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ์–ธ์ œ emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๊ณ , ์–ธ์ œ๋Š” ๊ตณ์ด ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋ ๊นŒ?

์ด ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต์€ Kafka์˜ ํŠน์„ฑ์ด ์•„๋‹ˆ๋ผ, ์šฐ๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์ „์†ก ๊ฒฐ๊ณผ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋‹ฌ๋ ค ์žˆ๋‹ค.



4-1. ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ฒฝ์šฐ


๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์ด๋ผ๋ฉด, emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ตณ์ด ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ํฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.

  • ์ด๋ฒคํŠธ๊ฐ€ ๋‹จ์ˆœํžˆ โ€œ์•Œ๋ฆผโ€ ์„ฑ๊ฒฉ์ธ ๊ฒฝ์šฐ
  • ์ „์†ก ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์น˜๋ช…์ ์ด์ง€ ์•Š์€ ๊ฒฝ์šฐ
  • ์‹คํŒจ ์—ฌ๋ถ€๋ฅผ ๋ณ„๋„์˜ ๋ชจ๋‹ˆํ„ฐ๋ง์ด๋‚˜ ์žฌ์ฒ˜๋ฆฌ๋กœ ๋ณด์™„ํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์‚ฌ์šฉ์ž ํ–‰๋™ ๋กœ๊ทธ ์ˆ˜์ง‘
  • ํ†ต๊ณ„์šฉ ์ด๋ฒคํŠธ ๋ฐœํ–‰
  • ์‹คํŒจํ•˜๋”๋ผ๋„ ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„์— ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š” ๋น„๋™๊ธฐ ์ž‘์—…

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์ž์ฒด๊ฐ€ ํ•ต์‹ฌ ๋กœ์ง์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, emit()์„ fire-and-forget ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•ด๋„ ์ถฉ๋ถ„ํžˆ ํ•ฉ๋ฆฌ์ ์ด๋‹ค.



4-2. ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ


๋ฐ˜๋Œ€๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ๋ผ๋ฉด emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

  • ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์„ฑ๊ณต ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ
  • ์ „์†ก ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„, ๋ณด์ƒ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ
  • โ€œ์ด ์ด๋ฒคํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ์ „๋‹ฌ๋˜์–ด์•ผ ํ•œ๋‹คโ€๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋Ÿฐ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

this.client.emit(topic, payload);
order.setPublished();  // ์ฃผ๋ฌธ ์ƒํƒœ ๋ณ€๊ฒฝ

์ด ์ฝ”๋“œ์—์„œ setPublished()๋Š” โ€œ์ฃผ๋ฌธ ์ด๋ฒคํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ฐœํ–‰๋˜์—ˆ๋‹คโ€๋Š” ์˜๋ฏธ๋กœ ์ฃผ๋ฌธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋กœ์ง์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Kafka ์ „์†ก์€ ์‹คํŒจํ–ˆ์ง€๋งŒ ์ฃผ๋ฌธ์€ ์ด๋ฏธ โ€œ๋ฐœํ–‰ ์™„๋ฃŒโ€ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋จ
  • ์ดํ›„ ์žฌ์‹œ๋„ ๋Œ€์ƒ์—์„œ๋„ ์ œ์™ธ๋จ

์ฆ‰, ์ „์†ก ์‹คํŒจ๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•œ ์ฑ„ ์ƒํƒœ๋งŒ ์•ž์„œ ๋‚˜๊ฐ€๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

import { lastValueFrom } from 'rxjs';

await lastValueFrom(this.client.emit(topic, payload));
order.setPublished();

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์œ„์™€ ๊ฐ™์ด emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ๋” ์•ˆ์ „ํ•˜๋‹ค.

๋‹ค๋งŒ, ํ•œ ๊ฐ€์ง€๋Š” ๋ถ„๋ช…ํžˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€์•ผ ํ•œ๋‹ค. emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค๊ณ  ํ•ด์„œ ์ปจ์Šˆ๋จธ์˜ ์ฒ˜๋ฆฌ ์„ฑ๊ณต๊นŒ์ง€ ๋ณด์žฅ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.



5. send vs emit โ€” ์šฐ๋ฆฌ๋Š” ์™œ emit์„ ์„ ํƒํ–ˆ์„๊นŒ?


emit()์˜ ๊ฒฐ๊ณผ๋ฅผ await ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋Ÿฐ ์งˆ๋ฌธ์ด ๋– ์˜ค๋ฅธ๋‹ค.

โ€œ๊ทธ๋ ‡๋‹ค๋ฉด send()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋” ์ ์ ˆํ•˜์ง€ ์•Š์„๊นŒ?โ€


send()์™€ emit()์€ ๋ชจ๋‘ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๋Š” API์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, ๋‘ ๋ฉ”์„œ๋“œ๋Š” ์ „ํ˜€ ๋‹ค๋ฅธ ํ†ต์‹  ๋ชจ๋ธ๊ณผ ์˜๋„๋ฅผ ์ „์ œ๋กœ ํ•œ๋‹ค.

send()๋Š” ์ƒ๋Œ€ ์„œ๋น„์Šค์˜ ์ฒ˜๋ฆฌ๋ฅผ ์ „์ œ๋กœ ํ•œ request-response ๋ฐฉ์‹์˜ ํ†ต์‹ ์ด๋‹ค.

const result = await this.client.send(pattern, payload);

์ด ๋ฐฉ์‹์—์„œ๋Š”,

  • ์š”์ฒญ์„ ๋ณด๋‚ธ ์ชฝ์ด ์ƒ๋Œ€ ์„œ๋น„์Šค์˜ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ 
  • ๊ทธ ์‘๋‹ต์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ ๋กœ์ง์„ ๊ฒฐ์ •ํ•œ๋‹ค.

์ฆ‰, ๋‘ ์„œ๋น„์Šค๋Š” ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋œ๋‹ค.

๋ฐ˜๋ฉด emit()์€ ์‘๋‹ต์„ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š๋Š” event-driven ๋ฐฉ์‹์˜ ํ†ต์‹ ์ด๋‹ค.

this.client.emit(topic, payload);

emit()์€,

  • โ€œ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ–ˆ๋‹คโ€๋Š” ์‚ฌ์‹ค์„ ์•Œ๋ฆด ๋ฟ
  • ๋ˆ„๊ฐ€ ์ด ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ• ์ง€๋Š” ์•Œ์ง€ ๋ชปํ•˜๊ณ 
  • ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์—ญ์‹œ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค

์ด ์ฐจ์ด๋Š” ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ DDD ๊ด€์ ์—์„œ ๋”์šฑ ๋ช…ํ™•ํ•ด์ง„๋‹ค. ์ด๋ฒคํŠธ๋Š” โ€œ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๊ฐ€ ์•Œ์•„์•ผ ํ•  ์‚ฌ์‹คโ€์„ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• ์ด์ง€, โ€œ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ผ๊ณ  ์ง€์‹œํ•˜๋Š” ๋ช…๋ นโ€์ด ์•„๋‹ˆ๋‹ค.

SNS ๋งˆ์ผ€ํŒ… ์ฃผ๋ฌธ ์ด๋ฒคํŠธ ์—ญ์‹œ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€๋‹ค. ์ฃผ๋ฌธ ์„œ๋น„์Šค๋Š” โ€œ์ฃผ๋ฌธ์ด ์ƒ์„ฑ๋˜์—ˆ๋‹คโ€๋Š” ์‚ฌ์‹ค์„ ์•Œ๋ฆด ๋ฟ, ์ฒ˜๋ฆฌ๋ฅผ ๋ˆ„๊ฐ€ ๋‹ด๋‹นํ• ์ง€, ์–ธ์ œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€๋Š” ๊ฐ๊ฐ์˜ ์ปจํ…์ŠคํŠธ(์‚ฌ๋‚ด ์„œ๋ฒ„ ํ˜น์€ ์™ธ๋ถ€ ๊ณต๊ธ‰์ž)์˜ ์ฑ…์ž„์ด๋‹ค.

์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ send()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฃผ๋ฌธ ์„œ๋น„์Šค๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‹ค๋ฅธ ์„œ๋น„์Šค์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋˜๊ณ , ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ request-response ํ˜•ํƒœ๋กœ ๊ธฐ์šธ ๊ฐ€๋Šฅ์„ฑ๋„ ์ƒ๊ธด๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ํ”ผํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.


๊ทธ๋ž˜์„œ ์„ ํƒํ•œ ๋ฐฉ์‹์ด emit()์„ ์‚ฌ์šฉํ•˜๋˜, ํ•„์š”ํ•  ๋•Œ๋งŒ ์ „์†ก ๊ฒฐ๊ณผ๋ฅผ await ํ•˜๋Š” ๊ตฌ์กฐ์˜€๋‹ค.

์ด ๋ฐฉ์‹์€

  • ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ
  • ์ตœ์†Œํ•œ์˜ ์ „์†ก ์ฑ…์ž„๋งŒ ํ™•์ธํ•˜๊ณ 
  • ์ดํ›„์˜ ์ฒ˜๋ฆฌ๋Š” ๊ฐ ์ปจํ…์ŠคํŠธ์— ์œ„์ž„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค

emit() + await๋Š” send()๋ฅผ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•œ ์„ ํƒ์ด๋ผ๊ธฐ๋ณด๋‹ค๋Š”, ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜์—์„œ ์ฑ…์ž„ ๊ฒฝ๊ณ„๋ฅผ ์กฐ๊ธˆ ๋” ๋ถ„๋ช…ํžˆ ํ•˜๊ธฐ ์œ„ํ•œ ์„ ํƒ์— ๊ฐ€๊นŒ์› ๋‹ค.



๐Ÿค” Understanding

์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๊ตฌ๋ถ„ emit() emit() + await send()
๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ๋ฐฉ์‹ Event-driven Event-driven Request-response
์‘๋‹ต ๊ธฐ๋Œ€ โŒ โŒ โญ•
await ์˜๋ฏธ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ ์ „์†ก ์‹คํŒจ ์—ฌ๋ถ€ ํ™•์ธ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์ˆ˜์‹ 
์ „์†ก ์„ฑ๊ณต ์˜๋ฏธ ๋ฐœํ–‰ ์‹œ๋„ ์ „์†ก์ด ์—๋Ÿฌ ์—†์ด ์™„๋ฃŒ๋จ ์ƒ๋Œ€ ์„œ๋น„์Šค ์ฒ˜๋ฆฌ ์™„๋ฃŒ
์ปจ์Šˆ๋จธ ์ฒ˜๋ฆฌ ๋ณด์žฅ โŒ โŒ โญ•
์„œ๋น„์Šค ๊ฐ„ ๊ฒฐํ•ฉ๋„ ๋‚ฎ์Œ ๋‚ฎ์Œ ๋†’์Œ
DDD ๊ด€์  Domain / Integration Event Domain / Integration Event Command
์ถ”์ฒœ ์‚ฌ์šฉ์ฒ˜ ๋กœ๊ทธ, ์•Œ๋ฆผ, ํ†ต๊ณ„ ์ƒํƒœ ๋ณ€๊ฒฝ์ด ์ˆ˜๋ฐ˜๋˜๋Š” ์ด๋ฒคํŠธ ๋™๊ธฐ ์ฒ˜๋ฆฌ ํ•„์š” ์‹œ

์ด ํ‘œ์—์„œ ๋ณด๋“ฏ, await๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ๋ฐฉ์‹ ์ž์ฒด๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. emit() + await ์—ญ์‹œ ์—ฌ์ „ํžˆ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹์ด๊ณ , ์šฐ๋ฆฌ๊ฐ€ ํ™•์ธํ•˜๋Š” ์ฑ…์ž„์˜ ๋ฒ”์œ„๋งŒ ์กฐ๊ธˆ ๋‹ฌ๋ผ์งˆ ๋ฟ์ด๋‹ค.

Kafka ๊ธฐ๋ฐ˜์˜ ์ด๋ฒคํŠธ ๋ฐœํ–‰์—์„œ โ€œ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ๋‹คโ€๋Š” ํ‘œํ˜„์€ ์ƒ๊ฐ๋ณด๋‹ค ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.

  • emit()์„ ๋‹จ์ˆœํžˆ ํ˜ธ์ถœํ–ˆ๋Š”์ง€,
  • emit()์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ ธ๋Š”์ง€,
  • ํ˜น์€ send()๋ฅผ ์„ ํƒํ–ˆ๋Š”์ง€์— ๋”ฐ๋ผ

ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„์™€ ์ฑ…์ž„์˜ ๋ฌด๊ฒŒ๋Š” ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ผ์ง„๋‹ค.



์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ์—์„œ ๋ฉ”์‹œ์ง€๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฒ˜๋ฆฌํ•ด ๋‹ฌ๋ผ๋Š” ์š”์ฒญ์ด๋ผ๊ธฐ๋ณด๋‹ค๋Š”, ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๋ฆฌ๋Š” ์ชฝ์— ๊ฐ€๊น๋‹ค.

์šฐ๋ฆฌ ํŒ€์€ ์ด ์‚ฌ์‹ค์„ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• ๊นŒ์ง€๋งŒ ๋งก๊ณ , ๊ทธ ์ดํ›„์˜ ์ฒ˜๋ฆฌ๋Š” ๊ฐ ์ปจํ…์ŠคํŠธ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งก๊ธฐ๊ณ  ์‹ถ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ send()๋ณด๋‹ค๋Š” emit()์„ ์„ ํƒํ–ˆ๊ณ , ์ƒํƒœ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ „์†ก ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ ๋” ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์„ ํƒํ–ˆ๋‹ค.

์ด ๊ธ€์ด Kafka์™€ NestJS๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ์ „์†ก์˜ ์˜๋ฏธ๋ฅผ ํ•œ ๋ฒˆ์ฏค ์ƒ๊ฐํ•ด๋ณด๋Š” ๊ณ„๊ธฐ๊ฐ€ ๋˜๊ณ , ์ด๋ฏธ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ํŒ€์—๊ฒŒ๋Š” ๊ฐ์ž์˜ ์„ ํƒ์„ ๋Œ์•„๋ณด๋Š” ์ฐธ๊ณ  ์ž๋ฃŒ ์ •๋„๊ฐ€ ๋˜๋ฉด ์ข‹๊ฒ ๋‹ค.

Previous
์ฒซ ์ด์ง ํ›„ ํšŒ๊ณ 
๐Ÿค”Retrospect
2025.12.08
Next
AI ์‹œ๋Œ€์— ๋‹ค์‹œ ๋– ์˜ฌ๋ฆฌ๊ฒŒ ๋œ "์žฅ์ธ ์ •์‹ "์ด๋ผ๋Š” ๊ธฐ์ค€
๐Ÿ“–Book
2026.01.04