You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

결함을 허용하지 않는 시스템은, 역설적으로 결함에 대응을 하지 않겠다란 의미입니다.

ActorSystem 은 결함을 허용함으로(결함을 발생시키겠다란 의미 아님)

장애발생시 감시할수있는 장치를 제공하고 , 사용자가 직접 대처할수 있는 디양한 전략을

선택하거나 응용프로그램에 설계할수가 있습니다.


장애 대응 설계


 액터 장애처리모델은 자기자신이 아닌 자신의 부모를 통해 정의가 가능하며

어떠한 액터의 장애를 다음과 같이 설계하고 룰을 정의한다고 합시다.

OOP 예외처리 모델에서 자식이 부모를 책임질수있는 구조적 정의는 불가능합니다.


다음과 같이, 장애대응 플랜을 세웠다고 가정해봅시다.

  • 장애 발생시 1분이내에 10번만 시도할수 있다. (복구 플랜)
  • 액터 작동시 널참조로인한 예외는 액터를 재시작한다.
  • 액터 작동시 인자값  익셉션 에러일시, 해당 액터를 Stop시킨다.


구현및 실행코드



    public class Supervisor : UntypedActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();        

        protected override SupervisorStrategy SupervisorStrategy()
        {
            return new OneForOneStrategy(
                maxNrOfRetries: 10,
                withinTimeRange: TimeSpan.FromMinutes(1),
                localOnlyDecider: ex =>
                {
                    log.Info("SomeException:" );
                    if( ex is ArithmeticException )
                        return Directive.Resume;
                    else if( ex is NullReferenceException)
                        return Directive.Restart;
                    else if (ex is ArgumentException)
                        return Directive.Stop;
                    else
                        return Directive.Escalate;                    
                });
        }
       

        protected override void OnReceive(object message)
        {
            if (message is string)
            {
                string msg = message as string;

                if ( msg.Contains("create-") )
                {
                    string childName = msg.Split('-')[1];
                    log.Info("CreateChildActor:" + childName);
                    var childActor = Context.ActorOf<Child>(childName);
                    Context.Watch(childActor);
                    Sender.Tell(childActor);
                }
                                
                
            }
        }
    }

    public class Child : UntypedActor
    {
        private int state = 0;
        private readonly ILoggingAdapter log = Context.GetLogger();

        protected override void OnReceive(object message)
        {            
            if( message is Exception)
            {
                throw message as Exception;
            }
            else if (message is int)
            {
                state = (int)message;
            }
            else if (message is string)
            {
                switch (message as string)
                {
                    case "get":
                        log.Info("Active Check");
                        Sender.Tell(state);
                        break;
                }
            }
        }

        protected override void PreRestart(Exception reason, object message)
        {
            log.Info("Actor Restart - reason:" + reason.GetType().Name );   //액터 재시작된 이전이유를 알수 있습니다.
        }
    }
            using (ActorSystem actorSystem = ActorSystem.Create("ServiceA"))
            {
                IActorRef supervisor = actorSystem.ActorOf<Supervisor>("supervisor");
                IActorRef child = supervisor.Ask("create-child1").Result as IActorRef;

                child.Tell(new NullReferenceException() );   //강제로 예외발생...                
                Task.Delay(1000).Wait();    //복구를 기다려준다.
                child.Tell("get");

                child.Tell(new ArgumentException() );   //강제로 예외발생...
                Task.Delay(1000).Wait();    //복구를 기다려준다.
                child.Tell("get");

                Task.Delay(3000).Wait();    //종료 지연시간

            }

[INFO][2017-09-13 오전 7:34:22][Thread 0029][[akka://ServiceA/user/supervisor#740151541]] CreateChildActor:child1
[INFO][2017-09-13 오전 7:34:22][Thread 0029][[akka://ServiceA/user/supervisor#740151541]] SomeException:
[ERROR][2017-09-13 오전 7:34:22][Thread 0029][akka://ServiceA/user/supervisor/child1] 개체 참조가 개체의 인스턴스로 설정되지 않았습니다.
Cause: System.NullReferenceException: 개체 참조가 개체의 인스턴스로 설정되지 않았습니다.
위치: ServiceA.STUDY.Child.OnReceive(Object message) 파일 D:\work\hobby\git.webnori.com\akkastudy\Solution\ServiceA\STUDY\SupervisorTestData.cs:줄 64
위치: Akka.Actor.UntypedActor.Receive(Object message)
위치: Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message)
위치: Akka.Actor.ActorCell.ReceiveMessage(Object message)
위치: Akka.Actor.ActorCell.Invoke(Envelope envelope)
[INFO][2017-09-13 오전 7:34:22][Thread 0029][[akka://ServiceA/user/supervisor/child1#716613491]] Actor Restart - reason:NullReferenceException
[INFO][2017-09-13 오전 7:34:23][Thread 0005][[akka://ServiceA/user/supervisor/child1#716613491]] Active Check
[INFO][2017-09-13 오전 7:34:23][Thread 0021][[akka://ServiceA/user/supervisor#740151541]] SomeException:
[ERROR][2017-09-13 오전 7:34:23][Thread 0021][akka://ServiceA/user/supervisor/child1] 값이 예상 범위를 벗어났습니다.
Cause: System.ArgumentException: 값이 예상 범위를 벗어났습니다.
위치: ServiceA.STUDY.Child.OnReceive(Object message) 파일 D:\work\hobby\git.webnori.com\akkastudy\Solution\ServiceA\STUDY\SupervisorTestData.cs:줄 64
위치: Akka.Actor.UntypedActor.Receive(Object message)
위치: Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message)
위치: Akka.Actor.ActorCell.ReceiveMessage(Object message)
위치: Akka.Actor.ActorCell.Invoke(Envelope envelope)
[INFO][2017-09-13 오전 7:34:23][Thread 0029][akka://ServiceA/deadLetters] Message Int32 from akka://ServiceA/user/supervisor/child1 to akka://ServiceA/deadLetters was not delivered. 1 dead letters encountered.
[INFO][2017-09-13 오전 7:34:24][Thread 0043][akka://ServiceA/user/supervisor/child1] Message String from akka://ServiceA/deadLetters to akka://ServiceA/user/supervisor/child1 was not delivered. 2 dead letters encountered.
[DEBUG][2017-09-13 오전 7:34:27][Thread 0044][ActorSystem(ServiceA)] Disposing system
[DEBUG][2017-09-13 오전 7:34:27][Thread 0044][ActorSystem(ServiceA)] System shutdown initiated





  • No labels