rwadurian/backend/services/reward-service/src/infrastructure/kafka/event-consumer.controller.ts

93 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Controller, Logger } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';
import { RewardApplicationService } from '../../application/services/reward-application.service';
import { EventAckPublisher } from './event-ack.publisher';
interface PlantingOrderPaidEvent {
eventName?: string;
data?: {
orderId: string;
userId: string;
treeCount: number;
provinceCode: string;
cityCode: string;
paidAt: string;
};
// 兼容旧格式
orderId?: string;
userId?: string;
treeCount?: number;
provinceCode?: string;
cityCode?: string;
paidAt?: string;
// B方案outbox 元数据
_outbox?: {
id: string;
aggregateId: string;
eventType: string;
};
}
@Controller()
export class EventConsumerController {
private readonly logger = new Logger(EventConsumerController.name);
constructor(
private readonly rewardService: RewardApplicationService,
private readonly eventAckPublisher: EventAckPublisher,
) {}
/**
* 监听认种订单支付成功事件
*/
@MessagePattern('planting.order.paid')
async handlePlantingOrderPaid(@Payload() message: PlantingOrderPaidEvent) {
this.logger.log(`Received planting.order.paid event: ${JSON.stringify(message)}`);
// 解析消息数据(支持新旧格式)
const eventData = message.data || {
orderId: message.orderId!,
userId: message.userId!,
treeCount: message.treeCount!,
provinceCode: message.provinceCode!,
cityCode: message.cityCode!,
paidAt: message.paidAt!,
};
// B方案提取 outbox 信息用于发送确认
const outboxInfo = message._outbox;
const eventId = outboxInfo?.aggregateId || eventData.orderId;
try {
// 1. 计算并分配奖励
await this.rewardService.distributeRewards({
sourceOrderId: BigInt(eventData.orderId),
sourceUserId: BigInt(eventData.userId),
treeCount: eventData.treeCount,
provinceCode: eventData.provinceCode,
cityCode: eventData.cityCode,
});
// 2. 检查该用户是否有待领取奖励需要转为可结算
await this.rewardService.claimPendingRewardsForUser(BigInt(eventData.userId));
this.logger.log(`Successfully processed planting.order.paid for order ${eventData.orderId}`);
// B方案发送处理成功确认
if (outboxInfo) {
await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
}
} catch (error) {
this.logger.error(`Error processing planting.order.paid:`, error);
// B方案发送处理失败确认
if (outboxInfo) {
const errorMessage = error instanceof Error ? error.message : String(error);
await this.eventAckPublisher.sendFailure(eventId, outboxInfo.eventType, errorMessage);
}
throw error;
}
}
}