DDD聚合协调器的Akka.net钝化(存储库)

时间:2016-03-04 21:34:02

标签: domain-driven-design ddd-repositories akka.net

我正在使用Akka.net并希望从我在此处看到的http://qnalist.com/questions/5585484/ddd-eventsourcing-with-akka-persistencehttps://gitter.im/petabridge/akka-bootcamp/archives/2015/06/25

中实现反应性等效的DDD存储库#39;

我理解有一个协调器可以根据一些实时内存计数或一些经过的时间将大量参与者留在内存中的想法。

作为摘要(基于上面的链接)我试图:

  1. 创建一个聚合协调器(针对每个actor类型),根据请求返回聚合。
  2. 每个聚合使用Context.SetReceiveTimeout方法来识别它是否在一段时间内未被使用。如果是这样,它将收到ReceiveTimeout消息。
  3. 收到超时消息后,Child会将一条Passivate消息发送回协调器(然后这将导致协调器关闭该子节点。)
  4. 当孩子被关闭时,协调员会拦截所有发送给孩子的消息并进行缓冲。
  5. 一旦确认了孩子的关闭(在协调员中),如果有该孩子的缓冲消息,则重新创建并将所有消息刷新到重新创建的孩子。
  6. 如何拦截正在尝试发送给孩子的消息(步骤4),而是将他们路由到父母?或者换句话说,我希望孩子在发送Passivate消息的时候说出来,然后说'#34; hey不要再发送给我了消息,而是发送给我的父母而不是"。

    这样可以节省我通过协调员路由所有内容(或者我是以错误的方式处理它而消息拦截无法做到,而应该通过父代理代理所有内容)?

    我有我的留言合同:

    public class GetActor
    {
        public readonly string Identity;
    
        public GetActor(string identity)
        {
            Identity = identity;
        }
    }
    
    public class GetActorReply
    {
        public readonly IActorRef ActorRef;
    
        public GetActorReply(IActorRef actorRef)
        {
            ActorRef = actorRef;
        }
    }
    
    public class Passivate // sent from child aggregate to parent coordinator
    {
    }
    

    Coordinator类,对于每种聚合类型都有一个唯一的实例:

    public class ActorLifetimeCoordinator r<T> : ReceiveActor where T : ActorBase
    {
        protected Dictionary<Identity,IActorRef> Actors = new Dictionary<Identity, IActorRef>();
        protected Dictionary<Identity, List<object>> BufferedMsgs = new Dictionary<Identity, List<object>>();
    
        public ActorLifetimeCoordinator()
        {
            Receive<GetActor>(message =>
            {
                var actor = GetActor(message.Identity);
                Sender.Tell(new GetActorReply(actor), Self); // reply with the retrieved actor
            });
    
            Receive<Passivate>(message =>
            {
                var actorToUnload = Context.Sender;
                var task = actorToUnload.GracefulStop(TimeSpan.FromSeconds(10));
    
                // the time between the above and below lines, we need to intercept messages to the child that is being
                // removed from memory - how to do this?
    
                task.Wait(); // dont block thread, use pipeto instead?
            });
        }
    
        protected IActorRef GetActor(string identity)
        {
            IActorRef value;
            return Actors.TryGetValue(identity, out value)
                ? value : Context.System.ActorOf(Props.Create<T>(identity));            
        }
    }
    

    汇总所有聚合的基类:

    public abstract class AggregateRoot : ReceivePersistentActor
    {
        private readonly DispatchByReflectionStrategy _dispatchStrategy
            = new DispatchByReflectionStrategy("When");      
    
        protected AggregateRoot(Identity identity)
        {
            PersistenceId = Context.Parent.Path.Name + "/" + Self.Path.Name + "/" + identity;
    
            Recover((Action<IDomainEvent>)Dispatch);
    
            Command<ReceiveTimeout>(message =>
            {
                Context.Parent.Tell(new Passivate());    
            });
    
            Context.SetReceiveTimeout(TimeSpan.FromMinutes(5));
        }
    
        public override string PersistenceId { get; }
    
        private void Dispatch(IDomainEvent domainEvent)
        {
            _dispatchStrategy.Dispatch(this, domainEvent);
        }
    
        protected void Emit(IDomainEvent domainEvent)
        {
            Persist(domainEvent, success =>
            {
                Dispatch(domainEvent);
            });
        }
    }
    

1 个答案:

答案 0 :(得分:1)

这里最简单(但不是最简单)的选项是使用Akka.Cluster.Sharding模块,该模块涵盖协调器模式的各个方面,支持角色分配和整个群集的平衡。

如果您选择不需要它,遗憾的是您需要通过协调员传递消息 - 消息本身需要提供用于确定收件人的标识符。否则你最终可能会向死去的演员发送消息。