NestJS CQRS EventHandler逻辑归属疑问:跨模块订阅还是本地处理?
在NestJS CQRS事件处理器中跨模块调用服务的最佳实践
你的初始判断是对的——严格遵循DDD原则的话,触发事件的模块的事件处理器不应该直接调用其他模块的服务,而是让其他模块通过订阅事件自行处理内部逻辑。
严守模块边界,符合单一职责
每个领域模块(比如你的Champion模块)只该聚焦自身核心业务。事件的作用是对外“告知发生了什么”,而不是直接指挥其他模块“该做什么”。要是在Champion模块的处理器里直接调用其他模块的服务,会把模块间的边界搅乱,导致耦合度飙升,后续改代码、加功能都会变得麻烦。正确的实现方式
先让Champion模块的ChampionAssignedHandler只处理和Champion自身相关的逻辑,比如更新Champion的状态、记录模块内的业务日志:import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; import { Logger } from '@nestjs/common'; import { ChampionAssignedPlayerEvent } from './champion-assigned.event'; import { ChampionService } from './champion.service'; @EventsHandler(ChampionAssignedPlayerEvent) export class ChampionAssignedHandler implements IEventHandler<ChampionAssignedPlayerEvent> { constructor(private readonly championService: ChampionService) {} async handle({ championId, playerId }: ChampionAssignedPlayerEvent) { // 只处理Champion模块内部逻辑 await this.championService.markAsAssigned(championId, playerId); Logger.log(`Champion ${championId} 已分配给玩家 ${playerId}`, 'ChampionAssignedHandler'); } }然后,任何需要响应这个事件的其他模块(比如Player模块),在自己模块里创建对应的事件处理器,订阅
ChampionAssignedPlayerEvent,再调用自身模块的服务完成业务:import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; import { ChampionAssignedPlayerEvent } from '../champion/champion-assigned.event'; import { PlayerService } from './player.service'; @EventsHandler(ChampionAssignedPlayerEvent) export class PlayerChampionAssignedHandler implements IEventHandler<ChampionAssignedPlayerEvent> { constructor(private readonly playerService: PlayerService) {} async handle({ championId, playerId }: ChampionAssignedPlayerEvent) { // Player模块内部处理逻辑 await this.playerService.updateChampionAssignment(playerId, championId); } }特殊情况的处理
如果是发送系统通知、记录全局操作日志这类通用基础设施操作,可以单独建一个基础设施模块,专门订阅各类事件来处理这些通用逻辑,别让业务模块和基础设施代码混在一起。
内容的提问来源于stack exchange,提问作者user1954784
相关产品推荐
相关产品推荐

