CQRS
CQRS
가장 간단한 CRUD 응용 프로그램의 흐름은 다음 단계를 사용하여 설명할 수 있습니다.
컨트롤러 계층은 HTTP 요청을 처리하고 작업을 서비스에 위임합니다.
서비스 계층은 대부분의 비즈니스 로직이 수행되는 장소입니다.
서비스 는 저장소 /DAO를 사용하여 엔티티를 변경/지속합니다.
엔티티는 setter 및 getter와 함께 값의 컨테이너 역할을합니다.
대부분의 경우 중소 규모의 응용 프로그램을 더 복잡하게 만들 이유가 없습니다. 그러나 때로는 충분하지 않으며 우리의 요구가 더 정교 해지고있을 때 데이터 흐름이 간단한 확장 가능한 시스템을 원합니다.
따라서 아래에서 설명하는 요소인 경량 CQRS 모듈을 제공합니다.
Commands
응용 프로그램을 이해하기 쉽게하려면 각 변경 사항 앞에 Command 가 있어야합니다. 명령이 전달될 때 응용 프로그램이 응답해야 합니다. 명령은 서비스 (또는 컨트롤러/게이트웨이에서 직접)에서 발송되고 해당하는 명령 처리기에서 사용될 수 있습니다.
@@filename(heroes-game.service)
@Injectable()
export class HeroesGameService {
constructor(private readonly commandBus: CommandBus) {}
async killDragon(heroId: string, killDragonDto: KillDragonDto) {
return this.commandBus.execute(
new KillDragonCommand(heroId, killDragonDto.dragonId)
);
}
}
@@switch
@Injectable()
@Dependencies(CommandBus)
export class HeroesGameService {
constructor(commandBus) {
this.commandBus = commandBus;
}
async killDragon(heroId, killDragonDto) {
return this.commandBus.execute(
new KillDragonCommand(heroId, killDragonDto.dragonId)
);
}
}다음은 KillDragonCommand를 전달하는 샘플 서비스입니다. 명령이 어떻게 보이는지 봅시다:
CommandBus는 스트림 명령입니다. 동등한 핸들러에 명령을 위임합니다. 각 명령에는 해당 명령 처리기가 있어야합니다.
이제 모든 애플리케이션 상태 변경은 Command 발생의 결과입니다. 로직은 핸들러에 캡슐화됩니다. 원하는 경우 여기에 로깅을 추가하거나 그 이상을 추가할 수 있으며 데이터베이스에 명령을 유지할 수 있습니다 (예: 진단 목적).
Events
처리기에 명령을 캡슐화했기 때문에 명령 구조 간의 상호 작용을 막을 수 있습니다. 응용 프로그램 구조는 응답 이 아니라 유연하지 않습니다. 해결책은 이벤트를 사용하는 것입니다.
이벤트는 비동기적입니다. models 또는 EventBus를 사용하여 직접 발송됩니다. 이벤트를 전달하려면 모델이 AggregateRoot 클래스를 확장해야 합니다.
apply()메소드는 모델과 EventPublisher 클래스 사이에 관계가 없기 때문에 아직 이벤트를 전달하지 않습니다. 모델과 게시자를 연결하는 방법은 무엇입니까? 커맨드 핸들러내에서 퍼블리셔 mergeObjectContext()메소드를 사용해야합니다.
이제 모든 것이 예상대로 작동합니다. 이벤트가 즉시 전달되지 않으므로 commit()이벤트가 필요합니다. 분명히, 객체는 선재할 필요가 없습니다. 타입 컨텍스트도 쉽게 병합할 수 있습니다 :
그게 전부입니다. 모델은 이제 이벤트를 게시할 수 있습니다. 그리고 우리는 그것들을 처리해야 합니다. 또한, 우리는 EventBus를 사용하여 수동으로 이벤트를 생성할 수 있습니다 :
info 힌트
이벤트 버스는 주입 가능한 클래스입니다.
각 이벤트에는 여러 개의 이벤트 핸들러가 있을 수 있습니다.
이제 write logic을 이벤트 핸들러로 옮길 수 있습니다.
Sagas
이 유형의 이벤트 중심 아키텍처는 응용 프로그램 응답성 및 확장성을 향상시킵니다. 이제 이벤트가 있을 때 다양한 방식으로 간단하게 반응할 수 있습니다. Sagas는 아키텍처 관점에서 마지막 빌딩 블록입니다.
Sagas는 엄청나게 강력한 기능입니다. Single saga는 1..* 이벤트를 수신 할 수 있습니다. [... ] 이벤트 스트림을 결합, 병합, 필터링 할 수 있습니다. RxJS 라이브러리는 마법의 근원입니다. 간단히 말해서, 각 saga는 명령이 포함된 Observable을 반환해야 합니다. 이 명령은 비동기적으로 전달됩니다.
info 힌트
ofType연산자는@nestjs/cqrs패키지에서 가져옵니다.
우리는 규칙을 선언했습니다 - 어떤 영웅이 용을 죽이면 고대 아이템이 떨어집니다. 그런 다음 적절한 처리기가 DropAncientItemCommand를 전달하고 처리합니다.
Queries
CqrsModule은 쿼리 처리에도 유용할 수 있습니다. QueryBus는 CommandsBus와 동일하게 작동합니다. 또한 쿼리 핸들러는 IQueryHandler 인터페이스를 구현하고 @QueryHandler()데코레이터로 표시해야 합니다.
Setup
우리가 마지막으로 돌봐야 할 것은 전체 메커니즘을 설정하는 것입니다.
Summary
CommandBus, QueryBus 및 EventBus는 관찰 가능(Observables)입니다. 이벤트 소싱을 통해 전체 스트림을 쉽게 구독하고 응용 프로그램을 보강할 수 있습니다.
실제 사례는 여기에서 확인할 수 있습니다.
Last updated
Was this helpful?