At-Least-Once Delivery - 적어도 메시지를 한번 보내려는 메카니즘으로 PersistenceActor와 결합하여

목표를 달성할수 있습니다. 보낼려는 메시지가 유실될수 있는 가능성을 제거하며

적어도 한번보내려는 메카니즘으로 인해 중복 메시지 발생에 유의하여 작성 해보겠습니다.


 이것은 메시지를 무조건 한번만 보내야할때 유용합니다. 아주 착한 택배 서비스 시나리오를 가정해봅시다.

택배 아저씨는 택배를 대상에게  일반적으로 아주 빠르게 대부분 성공을 하며, 물건 분실을

방지하고자 꼭 수신인 실명을 확인을 합니다. 하지만 받을사람이 부재중이라고 가정해봅시다.

택배 아저씨는 자신이 해야할  일을 하는동시에,  부재중을 체크하면서 보내려고 할것입니다.

결국 자신이 배달해야할 모든 택배를 모두 보내게 되며, 물건은 복제가 안되기때문에 중복없이

꼭 한번만 보내게 됩니다.  상대편이 선물을 받았나? 안받았나?

확인안하는 산타클로스 할아버지와는 다른 메카니즘입니다.


메시지설계

public class Msg
{
    public Msg(long deliveryId, string message)
    {
        DeliveryId = deliveryId;
        Message = message;
    }

    public long DeliveryId { get; }

    public string Message { get; }
}

public class Confirm
{
    public Confirm(long deliveryId)
    {
        DeliveryId = deliveryId;
    }

    public long DeliveryId { get; }
}

public interface IEvent
{

}

public class MsgSent : IEvent
{
    public MsgSent(string message)
    {
        Message = message;
    }

    public string Message { get; }
}

public class MsgConfirmed : IEvent
{
    public MsgConfirmed(long deliveryId)
    {
        DeliveryId = deliveryId;
    }

    public long DeliveryId { get; }
}



액터설계

public class ExampleDestinationAtLeastOnceDeliveryReceiveActor : ReceiveActor
{
    private ILoggingAdapter log = Context.GetLogger();
    protected int messageCnt = 0;
    public ExampleDestinationAtLeastOnceDeliveryReceiveActor()
    {
        Receive<Msg>(msg =>
        {
            messageCnt++;
            //Test를 위해 메시지를 못받은척한다.
            if (messageCnt % 2 ==0)
            {
                log.Warning("Test for Drop Message");
                return;
            }
                
            log.Debug("Yes I can");
            Sender.Tell(new Confirm(msg.DeliveryId), Self);
        });
    }
}

public class ExampleAtLeastOnceDeliveryReceiveActor : AtLeastOnceDeliveryReceiveActor
{
    private readonly IActorRef _destionationActor = Context.ActorOf<ExampleDestinationAtLeastOnceDeliveryReceiveActor>();
    private ILoggingAdapter log = Context.GetLogger();

    public ExampleAtLeastOnceDeliveryReceiveActor()
    {
        Recover<MsgSent>(msgSent => Handler(msgSent));
        Recover<MsgConfirmed>(msgConfirmed => Handler(msgConfirmed));

        Command<string>(str =>
        {
            log.Debug("received:" + str);
            Persist(new MsgSent(str), Handler);
        });

        Command<Confirm>(confirm =>
        {
            //메시지 받음을 확인하고, 해당 메시지를 더이상 안보낸다.
            log.Debug("received confirm:" + confirm.DeliveryId);
            Persist(new MsgConfirmed(confirm.DeliveryId), Handler);
        });
    }

    private void Handler(MsgSent msgSent)
    {
        Deliver(_destionationActor.Path, l => new Msg(l, msgSent.Message));
    }

    private void Handler(MsgConfirmed msgConfirmed)
    {
        ConfirmDelivery(msgConfirmed.DeliveryId);
    }

    public override string PersistenceId { get; } = "persistence-id";
}


TestCode

테스트 케이스

  • 메시지 10개를 한꺼번에 보낸다.
  • 받는 쪽에서 짝수번째 메시지를 못본채한다.( test 시나리오)
  • 우선 홀수 메시지는 모두 전송됨을 확인
  • 메시지 전송에 실패가난 짝수번째 메시지도 다시전송하여 결국 성공시킨다.(홀수번쨰 성공)


var actorInfo = Props.Create<ExampleAtLeastOnceDeliveryReceiveActor>();
var myactor = actorSystem.ActorOf(actorInfo, "myActor");
  for(int i=0;i<10;i++)
     myactor.Tell("can you speak english?");




  • No labels