NestJS Enterprise Backend APIs · 강의

서비스 간 통신

이벤트 기반 및 요청-응답 메커니즘을 포함하여 마이크로서비스 간의 효과적인 통신 패턴을 구현합니다.

레슨 3/312개 단계

서비스 간 통신은(는) CoddyKit의 무료 NestJS Enterprise Backend APIs 강의입니다. 이것은 3개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 NestJS Enterprise Backend APIs 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. NestJS Enterprise Backend APIs 강의에는 총 3개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Microservices Need to Talk

Microservices are designed to be independent, but they often need to collaborate to complete complex tasks. This means they must communicate with each other!

In this lesson, we'll explore the main patterns for how your NestJS microservices can send messages and share data effectively.

Sync vs. Async Communication

Understanding the difference between synchronous and asynchronous communication is crucial for microservices:

  • Synchronous: The sender waits for an immediate reply. It's like a direct phone call where you expect an answer right away.
  • Asynchronous: The sender doesn't wait for a reply. It's like sending an email – you send it and continue with other tasks, expecting a reply later (or not at all).

Both patterns have distinct use cases in a distributed system.

Request-Response Pattern

The Request-Response pattern is a synchronous communication method. One service (the client) sends a request to another service (the server) and pauses its own execution, waiting for a direct response.

  • Ideal for operations needing an immediate result.
  • Similar to how a typical web client interacts with a REST API.
  • Often implemented using HTTP, RPC, or message brokers configured for synchronous replies.

NestJS: Receiving Requests

In NestJS, a microservice listens for incoming requests using the @MessagePattern() decorator. This pattern must match the one sent by the client.

The decorated handler function receives the payload and returns a response. Try running this Product Service microservice:

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { Module, Controller, MessagePattern } from '@nestjs/common';

@Controller()
class ProductController {
  @MessagePattern('get_product_details')
  getProductDetails(id: string): any {
    console.log(`Product Service: Request for ID: ${id}`);
    const products = {
      '1': { id: '1', name: 'Laptop', price: 1200 },
      '2': { id: '2', name: 'Mouse', price: 25 },
    };
    return products[id] || { id, name: 'Product Not Found', price: 0 };
  }
}

@Module({
  controllers: [ProductController],
})
class AppModule {}

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options: { host: '127.0.0.1', port: 8877 },
    },
  );
  await app.listen();
  console.log('Product Microservice is listening on port 8877');
}

bootstrap();

NestJS: Sending Requests

To send a request to the 'Product Service' (from the previous scene), another microservice or an API Gateway uses a ClientProxy.

The client.send() method dispatches a message with a specific pattern and payload, returning an RxJS Observable that resolves with the response.

This snippet shows how a client service would initiate the request:

// product-client.service.ts in 'Order Service' microservice
import { Injectable, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { lastValueFrom } from 'rxjs'; // For awaiting observable

@Injectable()
export class ProductClientService {
  constructor(@Inject('PRODUCT_SERVICE') private client: ClientProxy) {}

  async fetchProduct(productId: string): Promise<any> {
    console.log(`Order Service: Fetching product ID: ${productId}`);
    // 'get_product_details' must match the pattern in Product Service
    const product = await lastValueFrom(
      this.client.send('get_product_details', productId),
    );
    console.log('Received product:', product);
    return product;
  }
}

// To make this work, 'PRODUCT_SERVICE' needs to be registered
// in an AppModule using ClientsModule.register():
// imports: [
//   ClientsModule.register([
//     {
//       name: 'PRODUCT_SERVICE',
//       transport: Transport.TCP,
//       options: { host: '127.0.0.1', port: 8877 },
//     },
//   ]),
// ],

When to Use Request-Response

The Request-Response pattern is best when:

  • You need an immediate answer from the target service.
  • The operation is critical and requires direct feedback (e.g., payment processing, user authentication).
  • You are fetching specific data from another service.
  • The interaction is a clear client-server relationship.

Be aware that this pattern introduces direct coupling between services.

Event-Based Communication

Event-based communication is an asynchronous pattern that uses a 'publish-subscribe' model. Services don't directly call each other; instead, they publish events to a message broker (like RabbitMQ) when something notable happens.

  • A service publishes an event (e.g., 'OrderCreated').
  • Other services subscribe to events they are interested in.
  • This pattern greatly decouples services, making them more independent.

NestJS: Publishing Events

To publish an event in NestJS, you use the client.emit() method of a ClientProxy. Unlike send(), emit() sends the event and immediately returns, not waiting for a response.

This 'fire-and-forget' approach is ideal for notifying other services about state changes. Run this Order Service that emits an event:

import { NestFactory } from '@nestjs/core';
import { Module, Controller, Post, Body, Inject } from '@nestjs/common';
import { ClientProxy, ClientsModule, Transport } from '@nestjs/microservices';

interface OrderCreatedEvent {
  orderId: string;
  userId: string;
  totalAmount: number;
}

@Controller('orders')
class OrderController {
  constructor(@Inject('NOTIFICATION_SERVICE') private client: ClientProxy) {}

  @Post()
  async createOrder(@Body() orderData: any) {
    const orderId = `ORD-${Date.now()}`;
    const event: OrderCreatedEvent = {
      orderId,
      userId: orderData.userId || 'user-123',
      totalAmount: orderData.amount || 100,
    };
    this.client.emit('order_created', event);
    console.log(`Order ${orderId} created, 'order_created' event emitted.`);
    return { message: 'Order created and event sent', orderId };
  }
}

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'NOTIFICATION_SERVICE',
        transport: Transport.TCP,
        options: { host: '127.0.0.1', port: 8878 },
      },
    ]),
  ],
  controllers: [OrderController],
})
class AppModule {}

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
  console.log('Order Service (HTTP) is listening on port 3000');
}

bootstrap();

NestJS: Listening to Events

Other microservices can subscribe to events using the @EventPattern() decorator. When an event with a matching pattern is emitted, the decorated method is automatically triggered.

This allows multiple services to react to the same event independently. Run this Notification Service to receive the event:

import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { Module, Controller, EventPattern } from '@nestjs/common';

interface OrderCreatedEvent {
  orderId: string;
  userId: string;
  totalAmount: number;
}

@Controller()
class NotificationController {
  @EventPattern('order_created')
  handleOrderCreated(data: OrderCreatedEvent) {
    console.log('Notification Service received OrderCreated event:', data);
    console.log(`Sending notification for Order ${data.orderId} to User ${data.userId}`);
  }
}

@Module({
  controllers: [NotificationController],
})
class AppModule {}

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options: { host: '127.0.0.1', port: 8878 },
    },
  );
  await app.listen();
  console.log('Notification Microservice is listening on port 8878');
}

bootstrap();

When to Use Event-Driven

Event-based communication is highly beneficial for:

  • Decoupling: Services don't need to know about each other, reducing dependencies.
  • Broadcasting: Notifying multiple consumers about a single event (e.g., 'UserRegistered' event).
  • Long-running processes: Initiating tasks that don't require an immediate response.
  • Resilience: Services can process events when they are available, improving fault tolerance.

It adds complexity but offers great flexibility and scalability.

Communication Patterns Quiz

Consider a scenario where an 'Order Service' needs to inform a 'Shipping Service' that an order is ready to be shipped, but the 'Order Service' doesn't need to wait for the shipping confirmation immediately. Which communication pattern is best suited for this?

Recap: Talking Services

Congratulations! You've learned about the fundamental patterns for inter-service communication in NestJS microservices.

  • Request-Response (using client.send() and @MessagePattern()) is for immediate, direct interactions where a reply is expected.
  • Event-Based (using client.emit() and @EventPattern()) is for asynchronous, decoupled communication via events, ideal for notifications and broadcasting.

Choosing the right pattern depends on your specific needs for coupling, responsiveness, and scalability in your distributed system.

무료로 시작

AI 튜터와 함께 TypeScript을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
20
레슨
76

자주 묻는 질문

“서비스 간 통신” 강의는 무료인가요?

네 — “서비스 간 통신” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 NestJS Enterprise Backend APIs 강의 전체를 잠금 해제할 수 있습니다. NestJS Enterprise Backend APIs 강의에는 총 3개의 강의가 포함되어 있습니다.

“서비스 간 통신”에서 뭘 배우나요?

이벤트 기반 및 요청-응답 메커니즘을 포함하여 마이크로서비스 간의 효과적인 통신 패턴을 구현합니다. 브라우저에서 직접 실행하는 실습 코드로 NestJS Enterprise Backend APIs을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

NestJS Enterprise Backend APIs을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 NestJS Enterprise Backend APIs은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 3번째 강의입니다.

“서비스 간 통신” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 NestJS Enterprise Backend APIs 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 NestJS Enterprise Backend APIs 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. NestJS 마이크로서비스 개요
  2. RabbitMQ 통합
  3. 서비스 간 통신
← NestJS Enterprise Backend APIs(으)로 돌아가기