Versions Compared

Key

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

...

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


토너 액터설계

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

...

Info

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

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

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

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


토너 액터 구현

액터 생성

Code Block
languagec#
themeEmacs
public class ActorProviders
{
    public delegate IActorRef PrinterActorProvider();

    public delegate IActorRef TonerActorProvider();
}			


services.AddAkkaActor<PrinterActorProvider>((provider, actorFactory) =>
{
    var printerActor = actorFactory.ActorOf(Props.Create(() => new PrinterActor()).WithRouter(new RoundRobinPool(1))
        ,"printer");  //여기서 printer라는 이름을 지정한것은 중요하며 나중에 이름만가지고 액터 참조를 얻을수 있습니다.
    return () => printerActor;
});

services.AddAkkaActor<TonerActorProvider>((provider, actorFactory) =>
{
    var tonerActor = actorFactory.ActorOf(Props.Create(() => new TonerActor()).WithRouter(new RoundRobinPool(1))
        , "toner");
    return () => tonerActor;
});

...

모든 액터는 이름지정이 가능하며 (없을시 랜덤),  이름을 통해 액터 참조를 쉽게 얻어 낼수 있습니다.


프린터 액터 수정

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

    //주소로 액터를 선택하기 : 장점 생성자에 참조객체를 가질필요가 없다.
    ActorSelection tonerActor = Context.System.ActorSelection("user/toner");                
    //토너를 비동기로 소모시킴
    tonerActor.Tell(1);

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

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

...

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


토너 액터 구현

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} 입니다.");
            }
        });
    }
}

...

  • 토너소모를 하기위해 int를 전송하는것이아닌 → 토너소모객체(TonerConsumption)를 정의하여 Tell 하는것이 권장됩니다.


작동결과