简体   繁体   中英

Sending an initial akka message

In below akka structure my Parent actor sends StartMessage to Parent actor which then sends ChildMessage to Child actor. On receiving ChildMessage a sys process to run an sh file is invoked : "/Users/setup.sh" !! In order to ensure the DoM message is sent after StartMessage I insert a Thread.sleep :

parentActor ! StartMessage

Thread.sleep(5000)

parentActor ! DoM

StartMessage is required to be sent initially as setup.sh executes initialization which the other actors rely upon. Is there an alternative mechanism which prevents from messages being send until an initial message is sent ?

All code :

import akka.actor.{Actor, ActorRef, ActorSystem, Props, _}
import akka.stream.ActorMaterializer

import scala.sys.process._

case object ChildMessage
case object ReplyMessage
case object StartMessage
case object StopMessage
case object DoM

class Parent(child: ActorRef) extends Actor {
  var count = 0
  def incrementAndPrint { count += 1; println("incrementing and printing") }
  def receive = {
    case StartMessage =>
      println("Received StartMessage in child")
      incrementAndPrint
      child ! ChildMessage
    case ReplyMessage =>
    case DoM =>
      println("DoM")
    case _ => println("Parent got something unexpected.")
  }
}

class Child extends Actor {
  def receive = {
    case ChildMessage =>
      println("Received Child Message")
      "/Users/setup.sh" !!

      sender ! ReplyMessage
    case StopMessage =>
      println("Received Stop Message")
      context.stop(self)
    case _ => println("Child got something unexpected.")
  }
}

object Question {

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("sys")
    implicit val materializer = ActorMaterializer.create(system)

    val childActor = system.actorOf(Props[Child], name = "RunServerC")
    val parentActor = system.actorOf(Props(new Parent(childActor)), name = "RunServerP")

    parentActor ! StartMessage

    Thread.sleep(5000)

    parentActor ! DoM


  }

}

You can change the behaviour of your actor by calling context.become . Also, you can define two new object s to use when an unexpected message is received:

object Parent {
  case object NotYetInitialised
  case object AlreadyInitialised
}

class Parent(child: ActorRef) extends Actor {
  def receive = {
    case StartMessage =>
      println("Received StartMessage")
      child ! ChildMessage
      context.become(initialised)
    case _ =>
      println("Parent got something unexpected.")
      sender ! Parent.NotYetInitialised
  }

  def initialised: Receive = {
    case ReplyMessage =>
    case DoM => println("DoM")
    case ResetMessage => context.become(receive) // I made it up
    case StartMessage => sender ! Parent.AlreadyInitialised
    case _   => println("Parent got something unexpected.")
  }
}

You can try Akkaask method to send messages to another actor but one thing you have to keep in mind is that the receiver actor must respond to the sender actor. So, in your case, you can either use ask as a sync call or an async call.

Ask Sync

Await.result(parentActor ? StartMessage, 10 seconds)

Ask Async

import akka.pattern.ask
import scala.util.{Failure, Success}
import akka.util.Timeout

implicit val timeout = Timeout(10 seconds)
(parentActor ? StartMessage).onComplete{
    case Success(value) =>
    case Failure(exception) => 

}(context.dispatcher)

And once you finished your work in the child actor reply to the parent actor by sending some message like sender() ! "Work is done" sender() ! "Work is done"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM