메시지가 발생할때 명령의 이벤트 목록을 생성하고 저장을 합니다.
이 계획은 이벤트만이 저장소에 추가되고 아무것도 변이되지 않는 점이며
이를 통해 이벤트 스트림의 소비자를 완벽하게 복제하고 확장할수 있습니다.
이벤트 소싱의 특징
- 개체-관계형 임피던스 불일치가 존재하지 않습니다.
- 신뢰할 수 있는 시스템 기록을 확보할 수 있습니다.
- 메시지 중심(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>());
});
}
}
}