Page History
...
Code Block | ||||
---|---|---|---|---|
| ||||
@Component @Scope("prototype") public class SnapShotActor extends AbstractPersistentActor { private final LoggingAdapter log = Logging.getLogger(getContext().system(), "AbstractPersistentActor"); private Object state; private int snapShotInterval = 5; private int msgCnt = 0; @Override public String persistenceId() { return "ExamplePersistentActor-id-1"; } @Override public Receive createReceiveRecover() { return receiveBuilder(). match(SnapshotOffer.class, s -> { state = s.snapshot(); //상태복원 log.info("상태복원"); // ... }). match(String.class, s -> {/* ...*/}).build(); } @Override //복구전략(스냅샷을 무시할수도 있음) public Recovery recovery() { //return Recovery.create(SnapshotSelectionCriteria.none()); return Recovery.create( SnapshotSelectionCriteria .create(457L, System.currentTimeMillis())); } // 스냅샷을 지원하는 메시지 정의 @Override public Receive createReceive() { return receiveBuilder(). match(SaveSnapshotSuccess.class, ss -> { SnapshotMetadata metadata = ss.metadata(); // ... }). match(SaveSnapshotFailure.class, sf -> { SnapshotMetadata metadata = sf.metadata(); // ... }). match(String.class, cmd -> { log.info("EventFired:"+cmd); if(cmd.indexOf("print") ==0 ) { //로그를 통해 확인하거나? log.info("상태확인:"+state); // 전송자에게 메시지를 통해 상태를 알려줌 sender().tell(state, ActorRef.noSender()); }else { msgCnt++; state = cmd + "을 먹은 상태"; //커멘드에따른 상태변화 log.info("ChangeStated" + state); if (msgCnt % snapShotInterval == 0 ) { //이벤트가 ?회 발생할때만,상태를 변경하고 스냅샷을 찍음 ( 순수스냅샷 테스트를 위해 persist기능을 뺏습니다.) 테스트 ) log.info("SaveSnapShot:" + state); saveSnapshot(state); } } }) .build(); } } |
이벤트를 받게되면, 상태가 변경되게되며 자신이 원하는 타이밍에
카메라 셔터(saveSnapshot) 를 누르기만 하면됩니다.
여기서는 수많은 이벤트를 모두 저장하는것은 비효율적이니, 매 5번째 상태의 스냅샷정보를 유지하기로 하였다고 가정하였습니다.
실제, 앞장 샘플에서는 persist기능과 연동되어 스냅샷과 상관없이 최근 X개 유지기능을 통해 , 마지막 상태복구가가능합니다.
스냅샷
...
복원전략
Code Block | ||||
---|---|---|---|---|
| ||||
private Object state;
@Override public Receive createReceiveRecover() {
return receiveBuilder().
match(SnapshotOffer.class, s -> {
state = s.snapshot();
// ...
}).
match(String.class, s -> {/* ...*/}).build();
}
또는
@Override
public Recovery recovery() {
return Recovery.create(
SnapshotSelectionCriteria
.create(457L, System.currentTimeMillis()));
} |
...
Code Block | ||||
---|---|---|---|---|
| ||||
protected void persistenceSnapShot() { new TestKit(system) {{ ActorRef probe = getRef(); Props snapShotActorProp = ext.props("snapShotActor"); System.out.println("===== snapShotActor 액터생성"); ActorRef snapShotActor = system.actorOf(snapShotActorProp, "snapShotActor"); System.out.println("===== event 생성"); snapShotActor.tell("커피", ActorRef.noSender()); snapShotActor.tell("사탕", ActorRef.noSender()); snapShotActor.tell("커피", ActorRef.noSender()); snapShotActor.tell("스테이크", ActorRef.noSender()); snapShotActor.tell("라면", ActorRef.noSender()); // <-- 복구기대 상태 snapShotActor.tell("사탕", ActorRef.noSender()); snapShotActor.tell("커피", ActorRef.noSender()); System.out.println("===== 상태확인"); snapShotActor.tell( "print" , ActorRef.noSender()); expectNoMessage(java.time.Duration.ofSeconds(1)); System.out.println("===== snapShotActor 종료또는 비정상종료"); snapShotActor.tell( akka.actor.PoisonPill.getInstance() , ActorRef.noSender()); expectNoMessage(java.time.Duration.ofSeconds(1)); System.out.println("snapShotActor===== 마지막 상태snapShotActor 확인재생성"); ActorRef snapShotActo2 = system.actorOf(snapShotActorProp, "eventActor"); System.out.println("===== 상태 복원확인 복원확인을 위해 probe를 액터 참조자로 지정"); snapShotActo2.tell( "print" , probe ActorRef.noSender()); // === 기대결과 1초이내에 '라면을 먹은 상태'임을 확인 : 비동기 메시지를 확인할수 있는 방법중하나 expectNoMessageexpectMsgEquals(java.time.Duration.ofSeconds(1)); , "라면을 먹은 상태" ); }}; } |
Expand | ||
---|---|---|
| ||
===== snapShotActor 액터생성 |
...