import { Injectable, Logger } from '@nestjs/common'; import { CDCEvent, TransactionClient } from '../../infrastructure/kafka/cdc-consumer.service'; import { ContributionAccountAggregate } from '../../domain/aggregates/contribution-account.aggregate'; /** * 用户 CDC 事件处理器 * 处理从身份服务同步过来的用户数据 * * 设计说明:100%同步数据,不跳过任何字段更新 */ @Injectable() export class UserSyncedHandler { private readonly logger = new Logger(UserSyncedHandler.name); constructor() {} async handle(event: CDCEvent, tx: TransactionClient): Promise { const { op, before, after } = event.payload; this.logger.log(`[CDC] User event received: op=${op}, seq=${event.sequenceNum}`); this.logger.debug(`[CDC] User event payload: ${JSON.stringify(after || before)}`); try { switch (op) { case 'c': // create case 'r': // read (snapshot) await this.handleCreate(after, event.sequenceNum, tx); break; case 'u': // update await this.handleUpdate(after, event.sequenceNum, tx); break; case 'd': // delete await this.handleDelete(before); break; default: this.logger.warn(`[CDC] Unknown CDC operation: ${op}`); } } catch (error) { this.logger.error(`[CDC] Failed to handle user CDC event, op=${op}, seq=${event.sequenceNum}`, error); throw error; } } private async handleCreate(data: any, sequenceNum: bigint, tx: TransactionClient): Promise { if (!data) { this.logger.warn(`[CDC] User create: empty data received`); return; } const userId = data.user_id ?? data.id; const accountSequence = data.account_sequence ?? data.accountSequence; const phone = data.phone_number ?? data.phone ?? null; const status = data.status ?? null; this.logger.log(`[CDC] User create: userId=${userId}, accountSequence=${accountSequence}, status=${status}`); if (!userId || !accountSequence) { this.logger.warn(`[CDC] Invalid user data: missing user_id or account_sequence`, { data }); return; } // 100%同步数据 await tx.syncedUser.upsert({ where: { accountSequence }, create: { originalUserId: BigInt(userId), accountSequence, phone, status, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, update: { originalUserId: BigInt(userId), phone, status, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, }); // 为用户创建算力账户(如果不存在) const existingAccount = await tx.contributionAccount.findUnique({ where: { accountSequence }, }); if (!existingAccount) { const newAccount = ContributionAccountAggregate.create(accountSequence); const persistData = newAccount.toPersistence(); await tx.contributionAccount.create({ data: persistData, }); this.logger.log(`[CDC] Created contribution account for user: ${accountSequence}`); } this.logger.log(`[CDC] User synced: ${accountSequence}`); } private async handleUpdate(data: any, sequenceNum: bigint, tx: TransactionClient): Promise { if (!data) { this.logger.warn(`[CDC] User update: empty data received`); return; } const userId = data.user_id ?? data.id; const accountSequence = data.account_sequence ?? data.accountSequence; const phone = data.phone_number ?? data.phone ?? null; const status = data.status ?? null; this.logger.log(`[CDC] User update: userId=${userId}, accountSequence=${accountSequence}, status=${status}`); if (!userId || !accountSequence) { this.logger.warn(`[CDC] Invalid user update data: missing user_id or account_sequence`, { data }); return; } // 100%同步数据 await tx.syncedUser.upsert({ where: { accountSequence }, create: { originalUserId: BigInt(userId), accountSequence, phone, status, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, update: { originalUserId: BigInt(userId), phone, status, sourceSequenceNum: sequenceNum, syncedAt: new Date(), }, }); this.logger.log(`[CDC] User synced: ${accountSequence}`); } private async handleDelete(data: any): Promise { if (!data) { this.logger.warn(`[CDC] User delete: empty data received`); return; } const accountSequence = data.account_sequence ?? data.accountSequence; // 用户删除一般不处理,保留历史数据 this.logger.log(`[CDC] User delete event received: ${accountSequence} (not processed, keeping history)`); } }