gRPC 함수 실행하기 - 44.OrderMicroservice 작업하기
1. 기존 구조
기존 OrderService는 사용자(User), 상품(Product), 결제(Payment) 서비스를 메시지 기반(ClientProxy)으로 호출했습니다.
// 기존 메시지 기반 호출 (주석 처리된 부분)
// this.userService.send({ cmd: 'get_user_info' }, { userId });
// this.productService.send({ cmd: 'get_products_info' }, { productIds });
// this.paymentService.send({ cmd: 'make_payment' }, { ...payload });
이 방식은 단순 이벤트 전달에는 유용했지만, 서비스 간 응답을 필요로 하는 주문 생성 프로세스에는 한계가 있었습니다.
2. gRPC 기반으로 전환
gRPC 클라이언트 주입
ClientGrpc를 사용해 User, Product, Payment 서비스와 직접 gRPC 통신을 하도록 수정합니다.
constructor(
@Inject(USER_SERVICE) private readonly userMicroService: ClientGrpc,
@Inject(PRODUCT_SERVICE) private readonly productMicroService: ClientGrpc,
@Inject(PAYMENT_SERVICE) private readonly paymentMicroService: ClientGrpc,
@InjectModel(Order.name)
private readonly orderModel: Model<Order>,
) {}
서비스 초기화
모듈 초기화 시점에 각 마이크로서비스의 gRPC Client를 가져옵니다.
onModuleInit() {
this.userService =
this.userMicroService.getService<UserMicroservice.UserServiceClient>(
'UserService',
);
this.productService =
this.productMicroService.getService<ProductMicroservice.ProductServiceClient>(
'ProductService',
);
this.paymentService =
this.paymentMicroService.getService<PaymentMicroservice.PaymentServiceClient>(
'PaymentService',
);
}
3. 주문 생성 프로세스
단계별 흐름
사용자 정보 가져오기
JWT 토큰을 파싱하고 사용자 정보를 gRPC로 요청합니다.
const user = await this.getUserFromToken(meta.user.sub);
상품 정보 가져오기
상품 ID 목록을 넘겨서 상세 정보를 gRPC로 요청합니다.
const products = await this.getProductsByIds(productIds);
총 금액 계산 및 검증
상품들의 가격 합계를 구하고, 프론트에서 전달된 결제 금액과 비교합니다.
const totalAmount = this.calculateTotalAmount(products); this.validatePaymentAmount(totalAmount, payment.amount);
주문 생성하기
DB에 주문 데이터를 저장합니다.
const customer = this.createCustomer(user); const order = await this.createNewOrder(customer, products, address, payment);
결제 시도하기
PaymentMicroservice의 makePayment RPC를 호출합니다.
const processPayment = await this.processPayment( order._id.toString(), payment, user.email, );
결과 반환
주문 객체를 DB에서 조회하여 반환합니다.
return this.orderModel.findById(order._id);
4. 세부 기능 구현
사용자 정보 가져오기
private async getUserFromToken(userId: string) {
const uResp = await lastValueFrom(this.userService.getUserInfo({ userId }));
return uResp;
}
상품 정보 가져오기
private async getProductsByIds(productIds: string[]): Promise<Product[]> {
const resp = await lastValueFrom(
this.productService.getProductsInfo({ productIds }),
);
return resp.products.map((product) => ({
productId: product.id,
name: product.name,
price: product.price,
}));
}
결제 처리하기
결제는 주문 생성의 핵심 단계입니다. 결제 실패 시 예외를 발생시키고 주문 상태를 업데이트합니다.
async processPayment(orderId: string, payment: PaymentDto, userEmail: string) {
try {
const resp = await lastValueFrom(
this.paymentService.makePayment({ ...payment, userEmail, orderId }),
);
const isPaid = resp.paymentStatus === 'Approved';
const orderStatus = isPaid
? OrderStatus.paymentProcessed
: OrderStatus.paymentFailed;
if (orderStatus === OrderStatus.paymentFailed) {
throw new PaymentFailedException(resp);
}
await this.orderModel.findByIdAndUpdate(orderId, {
status: OrderStatus.paymentProcessed,
});
return resp;
} catch (e) {
if (e instanceof PaymentFailedException) {
await this.orderModel.findByIdAndUpdate(orderId, {
status: OrderStatus.paymentFailed,
});
}
throw e;
}
}
5. 정리
이번 작업으로 OrderMicroservice도 gRPC 기반으로 전환되었습니다. 이로써 전체 서비스 흐름은 다음과 같이 연결됩니다:
UserMicroservice → 사용자 정보 조회
ProductMicroservice → 상품 정보 조회
PaymentMicroservice → 결제 처리
NotificationMicroservice → 결제/배송 알림
전환 효과
서비스 간 통신의 명확한 계약 보장 (proto 기반)
효율적인 데이터 교환 (HTTP/2 기반 gRPC)
전체 주문-결제-알림 플로우의 견고성과 신뢰성 강화













댓글 ( 0)
댓글 남기기