0Pricing
NestJS Enterprise Backend APIs · 课时

服务间通信

实现微服务之间高效通信的模式,包括基于事件的机制和请求—响应机制。

服务间通信 是 CoddyKit 上的免费 NestJS Enterprise Backend APIs 课时。 这是第 3 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 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 导师)并解锁 NestJS Enterprise Backend APIs 课程的其余内容,请升级到 CoddyKit PRO。 NestJS Enterprise Backend APIs 课程共包含 3 节课。

「服务间通信」这节课中我会学到什么?

实现微服务之间高效通信的模式,包括基于事件的机制和请求—响应机制。 你通过在浏览器中直接运行的动手代码来练习 NestJS Enterprise Backend APIs,全天候 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