From 875f86c263336c2f7b88815ddb391e9717d2fd7c Mon Sep 17 00:00:00 2001 From: hailin Date: Sun, 15 Feb 2026 07:59:16 -0800 Subject: [PATCH] =?UTF-8?q?fix(reporting):=20=E4=BF=AE=E5=A4=8D=20contract?= =?UTF-8?q?.signed=20=E4=BA=8B=E4=BB=B6=20BigInt(undefined)=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:planting-service 发送的 contract.signed 消息为嵌套结构 { eventName: 'contract.signed', data: { orderNo, userId, ... } } 但 reporting-service handleContractSigned 按扁平结构解析 message.userId → undefined → BigInt(undefined) → TypeError 导致 ~200 次/10分钟持续报错。 修复: - 消息类型改为匹配实际嵌套格式 { eventName, data: { ... } } - 解构 message.data 后再访问各字段 - 添加 userId 防御性检查,避免再次 BigInt 崩溃 - 与 referral-service ContractSigningHandler 消息结构保持一致 影响范围:仅 reporting-service 活动记录,不影响核心业务流程 (referral-service / reward-service 已正确处理嵌套格式) Co-Authored-By: Claude Opus 4.6 --- .../activity-event-consumer.controller.ts | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/backend/services/reporting-service/src/infrastructure/kafka/activity-event-consumer.controller.ts b/backend/services/reporting-service/src/infrastructure/kafka/activity-event-consumer.controller.ts index 555b7c77..39e2fe8d 100644 --- a/backend/services/reporting-service/src/infrastructure/kafka/activity-event-consumer.controller.ts +++ b/backend/services/reporting-service/src/infrastructure/kafka/activity-event-consumer.controller.ts @@ -637,47 +637,64 @@ export class ActivityEventConsumerController { /** * 监听合同签署事件 (planting-service) * Topic: contract.signed + * + * 消息格式(由 planting-service EventPublisherService.publishContractSigned 发送): + * { eventName: 'contract.signed', data: { orderNo, userId, accountSequence, ... } } + * + * 注意:实际 payload 嵌套在 data 字段下,与 referral-service ContractSigningHandler 一致。 + * 之前误用扁平结构导致 message.userId 为 undefined → BigInt(undefined) 抛出 + * TypeError (~200次/10分钟)。 */ @MessagePattern('contract.signed') async handleContractSigned( @Payload() message: { - orderNo: string; - userId: string; - accountSequence: string; - treeCount: number; - totalAmount: number; - provinceCode: string; - cityCode: string; - signedAt: string; + eventName: string; + data: { + orderNo: string; + userId: string; + accountSequence: string; + treeCount: number; + totalAmount: number; + provinceCode: string; + cityCode: string; + signedAt?: string; + }; }, ) { - this.logger.log(`Received contract.signed event: ${message.orderNo}`); + const eventData = message.data; + + if (!eventData?.userId) { + this.logger.warn(`Received contract.signed with missing data.userId, skipping. Raw: ${JSON.stringify(message)}`); + return; + } + + this.logger.log(`Received contract.signed event: ${eventData.orderNo}`); try { const created = await this.activityRepo.createIfNotExists({ activityType: 'contract_signed' as ActivityType, title: '合同签署', - description: `用户签署了 ${message.treeCount} 棵榴莲树认种合同`, + description: `用户签署了 ${eventData.treeCount} 棵榴莲树认种合同`, icon: '📝', - relatedUserId: BigInt(message.userId), + relatedUserId: BigInt(eventData.userId), relatedEntityType: 'contract', - relatedEntityId: message.orderNo, + relatedEntityId: eventData.orderNo, metadata: { - orderNo: message.orderNo, - accountSequence: message.accountSequence, - treeCount: message.treeCount, - totalAmount: message.totalAmount, - provinceCode: message.provinceCode, - cityCode: message.cityCode, - signedAt: message.signedAt, + orderNo: eventData.orderNo, + accountSequence: eventData.accountSequence, + treeCount: eventData.treeCount, + totalAmount: eventData.totalAmount, + provinceCode: eventData.provinceCode, + cityCode: eventData.cityCode, + signedAt: eventData.signedAt, }, }); if (created) { - this.logger.log(`Activity recorded for contract signing: ${message.orderNo}`); + this.logger.log(`Activity recorded for contract signing: ${eventData.orderNo}`); } else { - this.logger.log(`Skipped duplicate contract signing event: ${message.orderNo}`); + this.logger.log(`Skipped duplicate contract signing event: ${eventData.orderNo}`); } } catch (error) { this.logger.error(`Error recording contract signing activity:`, error);