Reputation: 53916
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
}
}
Upvotes: 0
Views: 568
Reputation: 1615
You can try Akka ask 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"
Upvotes: 1
Reputation: 3216
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.")
}
}
Upvotes: 1