Versions Compared

Key

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

이 장을 통해 추가적으로 알수 있는것

  • 액터를 선택하고 통신을 할수 있는 방법 ( actor ref vs actor selection)
  • 결과처리를 기달려야하는 경우와 아닌 경우 ( tell or ask)


토너 액터설계

프린터의 기능중, 토너의 용량을 관리하고 알려주는 기능부분을 분리하고 다음과 같이 설계해보자

...

Info

OOP 모델에서는 프린터가, 토너를 포함하고 있고 토너의 객체에 직접 접근하여 토너의량을 접근할수 있으며 프린터 모델에서는 그것이 더 심플하고 적합할수 있다. 

여기서는 프린터 모델을 설명하는 베스트 방법을 설명하려는것이 아니고, 액터 모델을 설명하기 위해 비교적 설명이 쉬울것같은 프린터를 대상으로 하였다.

토너 관리자가 단순하게 프린터 한대당 도킹되어 토너관리를 하느것이 아닌, 네트워크로 연결된 여러대의 프린터의 토너량을 관리해야하는 모델이라고가정해보자

OOP로 작성된 모델은 객체접근 밖에 되지 않기때문에 다시 작성되어야 할것이다.  


프린터 액터에 토너를 탑재하기

여기서 프린터와 액터는 어떠한 객체 디펜던시가 없기때문에 , 토너액터는 원격지로 분리도 가능합니다.

토너 액터 구현

Code Block
languagec#
themeEmacs
public class TonerActor : ReceiveActor
{
    private readonly ILoggingAdapter logger = Context.GetLogger();
    private readonly string id;
    private int tonerAmount = 5;

    public TonerActor()
    {
        id = Guid.NewGuid().ToString();
        logger.Info($"토너 액터 생성:{id}");
        ReceiveAsync<int>(async usageAmount =>
        {
            logger.Info($"토너 소모 :{usageAmount}");

            if (tonerAmount < 1)
            {
                //송신자 에게 이야기하기
                Sender.Tell("토너가 모두 소모되었습니다.");
            }
            tonerAmount -= usageAmount;                
        });

        ReceiveAsync<string>(async msg =>
        {
            if (msg == "남은용량?")
            {
                Sender.Tell($"남은 용량은 {tonerAmount} 입니다.");
            }
        });
    }
}

//토너액터생성
AkkaLoad.RegisterActor(
	"toner",
	actorSystem.ActorOf(Props.Create<TonerActor>()
		.WithRouter(new RoundRobinPool(1)),
		"toner"
));

...

  • 토너소모를 하기위해 int를 전송하는것이아닌 → 토너소모객체(TonerConsumption)를 정의하여 Tell 하는것이 권장됩니다.
  • Sender : 민수→영희 에게 질문을 하였다고 해봅시다. 최초 대화시작에서 민수는 영희를 지정할 필요가 있지만(액터선택) , 그것에 대한 영희의 응답은 대상지정이 아닌 나에게 질문을 한 대상자 즉 Sender이며 민수를 찾을 필요가 없습니다.
  • Foward : 민수→ 영희에게 길동의 나이를 알아봐죠 한경우 영희가 민수의 질문을 길동에게 전달하고 길동→민수 에게 답해야하는 상황으로 이 경우 Forward라고 합니다. 이것에 대한 로직은 이후 장에서 시도해보겠습니다.


프린터 액터 수정

Code Block
languagec#
themeEmacs
ReceiveAsync<PrintPage>(async page =>
{
    logger.Debug($"프린터 요청 들어옴:{page}");
    await Task.Delay(page.DelayForPrint);

    //주소로 액터를 선택하기 : 장점 생성자에 참조객체 디펜던시를 가질필요가 없다. ( DI로 동적인 디펜던시를 알아내기 어려울때 사용가능하며 위치 투명성을 보장합니다.)
    ActorSelection tonerActor = Context.System.ActorSelection("user/toner");                
    //토너를 비동기로 소모시킴
    tonerActor.Tell(1);

    //남은 토너 용량 물어봄
    var msg =await tonerActor.Ask("남은용량?");
    logger.Debug($"ASK결과:{msg}");

    logger.Debug($"페이지 출력 완료:{page}");
});

...

  • 민수야 너의 나이가 몇이니? :  민수야(액터선택)  너의 나이가 몇이니?( ASK )  - 응답을 기달림
  • 영희야 선생님이 찾으셔 교무실에 가봐 :  영희야(액터선택) 선생님이 찾으셔 교무실에 가봐( Tell) - 전달만함, 교무실에 실제로 갔는지 알필요없음


작동결과