NestJS CQRS自定义EventPublisher后事件处理器未触发,如何实现事件转发?
解决方案
问题出在你替换EventBus的默认publisher后,原有的事件分发逻辑被覆盖——你的自定义MongooseEventStore仅完成了数据库存储,没有触发事件处理器的逻辑。要实现先成功存库再触发处理器,可以通过包装默认事件发布器的方式实现:
1. 修改自定义EventStore,整合默认发布逻辑
让MongooseEventStore注入默认的EventPublisher,在自身的publish方法中先完成数据库存储,再调用默认发布器的publish触发事件处理器:
import { Injectable, EventPublisher } from '@nestjs/cqrs'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; // 假设你已定义事件的Mongoose模型 import { EventDocument, Event } from './schemas/event.schema'; @Injectable() export class MongooseEventStore implements EventPublisher { constructor( private readonly defaultPublisher: EventPublisher, @InjectModel(Event.name) private eventModel: Model<EventDocument> ) {} async publish<T>(event: T): Promise<void> { // 第一步:将事件存入数据库 await this.persistEvent(event); // 第二步:调用默认发布器,触发事件处理器 await this.defaultPublisher.publish(event); } // 批量发布逻辑同理 async publishAll<T>(events: T[]): Promise<void> { for (const event of events) { await this.publish(event); } } // 实际数据库存储逻辑 private async persistEvent(event: any) { const eventDoc = new this.eventModel({ eventType: event.constructor.name, payload: event.payload, occurredAt: new Date(), }); await eventDoc.save(); // 若存库失败会抛出错误,中断后续发布,保证数据一致性 } }
2. 保持模块配置,确保事件处理器注册
你的UsersModule配置无需大幅修改,只需确保onModuleInit中正确注册事件处理器:
@Module({ imports: [CqrsModule, DatabaseModule], controllers: [UsersController], providers: [ TransactionsService, AccountRepository, MongooseEventStore, ...CommandHandlers, ...EventHandlers, ...accountsProvider, ], }) export class UsersModule implements OnModuleInit { constructor( private readonly eventBus: EventBus, private readonly eventStore: MongooseEventStore, ) {} onModuleInit() { this.eventBus.publisher = this.eventStore; // 必须注册事件处理器数组 this.eventBus.register(EventHandlers); } }
关键逻辑说明
- 一致性保障:如果数据库存储失败,
persistEvent会抛出错误,后续的defaultPublisher.publish不会执行,避免出现「事件未存库但处理器已执行」的不一致情况。 - 原生逻辑复用:通过注入默认
EventPublisher,无需自行实现事件分发逻辑,直接复用NestJS CQRS的原生能力。
内容的提问来源于stack exchange,提问作者Paul Serre
相关产品推荐
相关产品推荐

