메시지가 발생할때 명령의 이벤트 목록을 생성하고 저장을 합니다.
이 계획은 이벤트만이 저장소에 추가되고 아무것도 변이되지 않는 점이며
이를 통해 이벤트 스트림의 소비자를 완벽하게 복제하고 확장할수 있습니다.
이벤트 소싱의 특징
- 개체-관계형 임피던스 불일치가 존재하지 않습니다.
- 신뢰할 수 있는 시스템 기록을 확보할 수 있습니다.
- 메시지 중심(message-driven) 아키텍처에 적합합니다.
- 저장소 규모를 확장하기 쉽습니다.
- CRUD가 아닌 CQRS의 한종류입니다.
이벤트 소싱을 위한 부가적인 기능
- 이벤트를 저장하고 복구하는방법
- 이벤트를 무한하게 재생할수 없음으로, 스냅샷을 이용하는 방법
유닛테스트를 통해 살펴보는 장바구니 이벤트 소싱
namespace AkkaNetCoreTest.Actors { public class PersistentActorTest : TestKitXunit { protected TestProbe probe; protected IActorRef persistentActor; public PersistentActorTest(ITestOutputHelper output) : base(output) { Setup(); } public void Setup() { //여기서 관찰자는 장바구니에 담긴 상품수를 검사할수 있습니다. probe = this.CreateTestProbe(); persistentActor = Sys.ActorOf(Props.Create(() => new MyPersistentActor(probe)), "persistentActor"); } //이벤트 소싱 테스트 [Theory(DisplayName = "이벤트소싱-이벤트는 상태화되고 재생되고 복구되어야한다")] [InlineData(5)] public void Test1(int cutoffSec) { // usage int expectedCount = 2; //선택 장애 장바구니 이벤트 Cmd cmd1 = new Cmd("장바구니를 물건을 담음+1"); Cmd cmd2 = new Cmd("장바구니에 물건을 뺌-0"); Cmd cmd3 = new Cmd("장바구니에 물건을 담음+1"); Cmd cmd4 = new Cmd("장바구니에 물건을 담음+2"); Within(TimeSpan.FromSeconds(cutoffSec), () => { persistentActor.Tell(cmd1); persistentActor.Tell(cmd2); persistentActor.Tell(cmd3); persistentActor.Tell(cmd4); persistentActor.Tell("print"); //현재까지 액터가 가진 이벤트리스트를 재생합니다. Assert.Equal(expectedCount, probe.ExpectMsg<int>()); //액터를 강제로 죽입니다. persistentActor.Tell(Kill.Instance); Task.Delay(500).Wait(); //시스템 셧다운후,재시작 시나리오 //액터를 다시생성하여, 액터가 가진 이벤트가 복구되는지 확인합니다. persistentActor = Sys.ActorOf(Props.Create(() => new MyPersistentActor(probe)), "persistentActor"); persistentActor.Tell("print"); Assert.Equal(expectedCount, probe.ExpectMsg<int>()); }); } } }