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?");