import { Injectable, Logger } from '@nestjs/common'; import { CDCEvent } from '../../infrastructure/kafka/cdc-consumer.service'; import { SyncedDataRepository } from '../../infrastructure/persistence/repositories/synced-data.repository'; import { ContributionAccountRepository } from '../../infrastructure/persistence/repositories/contribution-account.repository'; import { ContributionAccountAggregate } from '../../domain/aggregates/contribution-account.aggregate'; import { UnitOfWork } from '../../infrastructure/persistence/unit-of-work/unit-of-work'; /** * 用户 CDC 事件处理器 * 处理从身份服务同步过来的用户数据 */ @Injectable() export class UserSyncedHandler { private readonly logger = new Logger(UserSyncedHandler.name); constructor( private readonly syncedDataRepository: SyncedDataRepository, private readonly contributionAccountRepository: ContributionAccountRepository, private readonly unitOfWork: UnitOfWork, ) {} async handle(event: CDCEvent): 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); break; case 'u': // update await this.handleUpdate(after, event.sequenceNum); 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): Promise { if (!data) { this.logger.warn(`[CDC] User create: empty data received`); return; } // 兼容不同的字段命名(CDC 使用 snake_case) 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 ?? 'ACTIVE'; this.logger.log(`[CDC] User create: userId=${userId}, accountSequence=${accountSequence}, phone=${phone}, status=${status}`); if (!userId || !accountSequence) { this.logger.warn(`[CDC] Invalid user data: missing user_id or account_sequence`, { data }); return; } await this.unitOfWork.executeInTransaction(async () => { // 保存同步的用户数据 this.logger.log(`[CDC] Upserting synced user: ${accountSequence}`); await this.syncedDataRepository.upsertSyncedUser({ originalUserId: BigInt(userId), accountSequence, phone, status, sourceSequenceNum: sequenceNum, }); // 为用户创建算力账户(如果不存在) const existingAccount = await this.contributionAccountRepository.findByAccountSequence(accountSequence); if (!existingAccount) { const newAccount = ContributionAccountAggregate.create(accountSequence); await this.contributionAccountRepository.save(newAccount); this.logger.log(`[CDC] Created contribution account for user: ${accountSequence}`); } else { this.logger.debug(`[CDC] Contribution account already exists for user: ${accountSequence}`); } }); this.logger.log(`[CDC] User synced successfully: ${accountSequence}`); } private async handleUpdate(data: any, sequenceNum: bigint): Promise { if (!data) { this.logger.warn(`[CDC] User update: empty data received`); return; } // 兼容不同的字段命名(CDC 使用 snake_case) 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 ?? 'ACTIVE'; 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; } await this.syncedDataRepository.upsertSyncedUser({ originalUserId: BigInt(userId), accountSequence, phone, status, sourceSequenceNum: sequenceNum, }); this.logger.log(`[CDC] User updated successfully: ${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)`); } }