How to deal with long initialization of an Akka child actor?

后端 未结 3 880
醉酒成梦
醉酒成梦 2021-02-02 15:36

I have an actor which creates a child actor to perform some lengthy computations.

The problem is that the initialization of the child actor takes a few seconds and all

3条回答
  •  庸人自扰
    2021-02-02 16:27

    I think what you might be looking for is the combo of Stash and become. The idea will be that the child actor will set it's initial state to uninitialized, and while in this state, it will stash all incoming messages until it is fully initialized. When it's fully initialized, you can unstash all of the messages before swapping behavior over to the initialized state. A simple example is as follows:

    class ChildActor2 extends Actor with Stash{
      import context._
      var dep:SlowDependency = _
    
      override def preStart = {
        val me = context.self
        Future{
          dep = new SlowDependency
          me ! "done"
        }
      }
    
      def uninitialized:Receive = {
        case "done" => 
          unstashAll
          become(initialized) 
        case other => stash()
      }
    
      def initialized:Receive = {
        case "a" => println("received the 'a' message")
        case "b" => println("received the 'b' message")   
      }
    
      def receive = uninitialized
    }
    

    Notice in the preStart that I'm doing my initialization asynchronously, so as to not halt the startup of the actor. Now this is a bit ugly, with closing over the mutable dep var. You could certainly handle it by instead sending a message to another actor that handles instantiation of the slow dependency and sends it back to this actor. Upon receiving the dependency, it will then call become for the initialized state.

    Now there is one caveat with Stash and I'll paste it in right from the Akka docs:

    Please note that the Stash can only be used together with actors that 
    have a deque-based mailbox. For this, configure the mailbox-type of the 
    dispatcher to be a deque-based mailbox, such as 
    akka.dispatch.UnboundedDequeBasedMailbox (see Dispatchers (Scala)). 
    

    Now if this does not suite you, you can try a more DI type approach and let the slow dependency be injected into the child actor via it's constructor. So you would define the child actor like so:

    class ChildActor(dep:SlowDependency) extends Actor{
        ...
    } 
    

    Then when starting up this actor, you would do it as follows:

    context.actorOf(new Props().withCreator(new ChildActor(slowDep)), name = "child-actor")
    

提交回复
热议问题