Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
themeEmacs
@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
languagejava
themeEmacs
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
languagejava
themeEmacs
	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
title수행결과

===== snapShotActor 액터생성
===== event 생성
===== 상태확인
[INFO] [06/1720/2018 1509:4322:1034.283811] [AkkaTestApp-akka.actor.default-dispatcher-52] [AbstractPersistentActor] 상태복원
[INFO] [06/1720/2018 1509:4322:1034.398830] [AkkaTestApp-akka.actor.default-dispatcher-43] [AbstractPersistentActor] EventFired:커피
[INFO] [06/17/2018 15:43:10.400/20/2018 09:22:34.830] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated커피을 먹은 상태
[INFO] [06/20/2018 09:22:34.830] [AkkaTestApp-akka.actor.default-dispatcher-43] [AbstractPersistentActor] EventFired:사탕
[INFO] [06/20/2018 09:22:34.830] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated사탕을 먹은 상태
[INFO] [06/1720/2018 1509:4322:1034.400831] [AkkaTestApp-akka.actor.default-dispatcher-43] [AbstractPersistentActor] EventFired:커피
[INFO] [06/20/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated커피을 먹은 상태
[INFO] [06/1720/2018 1509:4322:1034.400831] [AkkaTestApp-akka.actor.default-dispatcher-43] [AbstractPersistentActor] EventFired:스테이크
[INFO] [06/17/2018 15:43:10.40320/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated스테이크을 먹은 상태
[INFO] [06/20/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] EventFired:라면
[INFO] [06/20/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated라면을 먹은 상태
[INFO] [06/1720/2018 1509:4322:1034.403831] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] SaveSnapShot:라면을 먹은 상태
[INFO] [06/1720/2018 1509:4322:1034.405831] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] EventFired:사탕
[INFO] [06/17/2018 15:43:10.40520/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated사탕을 먹은 상태
[INFO] [06/20/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] EventFired:커피
[INFO] [06/20/2018 09:22:34.831] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] ChangeStated커피을 먹은 상태
[INFO] [06/1720/2018 1509:4322:1034.406832] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] EventFired:print
[INFO] [06/1720/2018 1509:4322:1034.406832] [AkkaTestApp-akka.actor.default-dispatcher-53] [AbstractPersistentActor] 상태확인:라면을 커피을 먹은 상태
===== snapShotActor 종료또는 비정상종료
snapShotActor 마지막 상태 확인
상태 복원확인===== snapShotActor 재생성
===== 상태 복원확인을 위해 probe를 액터 참조자로 지정
[INFO] [06/1720/2018 1509:4322:1136.887754] [AkkaTestApp-akka.actor.default-dispatcher-23] [AbstractPersistentActor] 상태복원
[INFO] [06/1720/2018 1509:4322:1136.889755] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] EventFired:print
[INFO] [06/1720/2018 1509:4322:1136.889755] [AkkaTestApp-akka.actor.default-dispatcher-3] [AbstractPersistentActor] 상태확인:라면을 먹은 상태

...