I read about dangerous case there.
Now, I'm working on an extension which is supposed to trace incoming messages. I.e. when a message arrive I have to notify some external system that the message's arrived.
Is it safe to create actor object within another actor and pass it to props factory?
class HandlingActorWrapper(val decoratee: Actor) extends Actor {
override def receive: Receive = {
System.out.println("Message recieved");
decoratee.receive
}
}
object HandlingActorWrapper{
def props(actor: Actor) = Props(new HandlingActorWrapper(actor))
}
class MyActor extends Actor {
override def receive: Receive = {
//handling messages
}
}
class SomeActor extends Actor {
var child : ActorRef = _
override def preStart() = {
//>>|HERE
child = context.system.actorOf(HandlingActorWrapper.props(new MyActor))
}
//other
}
Related
I have a parent actor which creates a child actor and the child actor greets parent every minute as below
class MasterActor extends Actor with ActorLogging {
override def receive: Receive = {
case "Greet" =>
print("Hey child!!")
case "CreateChild" =>
context.actorOf(Props[ChildActor])
}
}
class ChildActor extends Actor with ActorLogging {
import context.dispatcher
override def preStart(): Unit = {
super.preStart()
context.system.scheduler.schedule(Duration("1 minutes").asInstanceOf[FiniteDuration],
Duration("1 minutes").asInstanceOf[FiniteDuration], context.parent, "Greet")
}
override def receive: Receive = {
case _ =>
print("child receives something")
}
}
I am new to actor system, How can I test schedule scenario using TestKit?
I tried something like below in my test but that is not working
"Master actor" should {
"receive a Greet message every minute" in {
val probe = TestProbe
val actor = system.actorOf(Props(new Child() {
import context.dispatcher
override def preStart() =
context.system.scheduler.scheduleOnce(Duration("1 seconds").asInstanceOf[FiniteDuration], probe.ref, "Greet")
}))
probe.expectMsg("Greet")
}
}
You can read about it at the timing-assertions section in the testing of akka docs. There is the within function that should help you.
For example you can try:
"Master actor" should {
"receive a Greet message every minute" in {
within(62 seconds) {
val probe = TestProbe
val actor = system.actorOf(Props[Child])
probe.expectMsg("Greet")
}
}
}
What I would do, not to wait so long, is putting the delay timeout in the configuration, and change it to a few millis in the test scenario.
I am trying to create a web socket server using Play Framework where response from server should be synchronous or asynchronous based on request.
The request will be processed in Parent actor .Based on the action in the request, child actor will be created and message will be passed to child actor for processing and response will be sent back to the controller.
There are predefined actions and sample request for some actions are as follows,
[,,]
["1234","Boot","{"system":"ABCD"}"]
["5678","Start","{"system":"EFGH", "currenTime":"1559548762638"}"]
#Singleton
class RequestController #Inject()(cc: ControllerComponents)(implicit system: ActorSystem, mat: Materializer) extends AbstractController(cc) {
def ws = WebSocket.accept[String, String] {req =>
ActorFlow.actorRef { out =>
ParentActor.props(out)
}
}
}
object ParentActor {
def props(out: ActorRef) = Props(new ParentActor(out))
}
class ParentActor(out : ActorRef) extends Actor {
override def receive: Receive = {
case msg: String =>
//String split opeartion to find the action.
//create child actor for the action and pass the message to the child actor
val action = msg.split(",")[2]
if("Boot".equals(action)){
val bootActor: ActorRef = actorSystem.actorOf(Props[BootActor])
childActor ! msg
}else if("Start".equals(action)){
val startActor: ActorRef = actorSystem.actorOf(Props[StartActor])
startActor ! msg
}
case msg: Response => out ! msg
}
}
case class Response(name:String, msg:String)
class BootActor extends Actor{
override def receive: Receive = {
case msg : String =>
sender() ! Response("ABC",msg)
}
}
class StartActor extends Actor{
override def receive: Receive = {
case msg : String =>
sender() ! Response("Efgh",msg)
}
}
Right now i am getting the action from the request and create a child actor for the action and pass the message to the child actor for processing.
But i am not sure is there any better way or design pattern to process the request and create a child actor instead of String operation?
First of all, there appears to be a typo in your code:
if ("Boot".equals(action)) {
val bootActor: ActorRef = actorSystem.actorOf(Props[BootActor])
childActor ! msg
} else if ("Start".equals(action)) {
val startActor: ActorRef = actorSystem.actorOf(Props[StartActor])
startActor ! msg
}
The message in the first conditional clause should be sent to bootActor instead of childActor, which is undefined in your code snippet.
Another issue is that you're using actorSystem.actorOf to create the child actors. This method creates "top-level" actors, which should be kept to a minimum. Actors created with actorSystem.actorOf are under the supervision of the guardian actor. What this means in relation to your code is that when ParentActor is stopped (i.e., when a WebSocket is closed, Play stops the actor used in ActorFlow, as documented here), the multiple instances of BootActor and StartActor will not be stopped, leaving you with a bunch of idle top-level actors. The remedy is to use context.actorOf to create instances of BootActor and StartActor: doing so makes these instances children of ParentActor.
Also, you should use the == operator instead of the equals method.
Here are the aforementioned changes:
if ("Boot" == action) {
val bootActor: ActorRef = context.actorOf(Props[BootActor])
bootActor ! msg
} else if ("Start" == action) {
val startActor: ActorRef = context.actorOf(Props[StartActor])
startActor ! msg
}
The above could be slightly simplified to the following:
val childActor =
if (action == "Boot") context.actorOf(Props[BootActor])
else context.actorOf(Props[StartActor])
childActor ! msg
To further simplify your code, don't create child actors, which in this case aren't necessary. Move all the logic of interacting with the out actor into a single actor.
I'm new to akka and I'm wondering how to get a child actor to receive messages.
I have one parent actor which prints out that it received a message and then sends a message to its child which then prints out that it received a message.
When I run the program, only the parent actor prints its message. Is there
something I'm missing?
The parent actor
class TestDirector(name: String) extends Actor {
import TestDirector._
implicit val timeout = Timeout(5.seconds)
private var child: ActorRef = _
override def preStart(): Unit = {
println(name + " pre-start")
child = context.actorOf(props("test-file"), name = "child-actor")
}
override def receive: Receive = {
case TestDirectory(dir) =>
println("Test Director")
child ! TestWorker.TestFile
}
}
object TestDirector {
case class TestDirectory(dirName: String)
case class TestResponse(message: String)
def props(dirName: String) = Props(classOf[TestDirector], dirName)
}
The child actor
class TestWorker(fileName: String) extends Actor {
import TestWorker._
override def receive: Receive = {
case TestFile => println("Hello world")
}
}
object TestWorker {
case object TestFile
def props(fileName: String) = Props(classOf[TestWorker], fileName)
}
In TestDirector.preStart, you say
child = context.actorOf(props("test-file"), name = "child-actor")
Those "props" are TestDirector.props, which you imported a few lines above, so you're endlessly creating new TestDirectors. I think what you want instead is TestWorker.props:
child = context.actorOf(TestWorker.props("test-file"), name = "child-actor")
I have the following actor code:
class MyActor #Inject()(dao1: MyDao, dao2: OtherDao, eventBus: EventBus) extends Actor with ActorLogging {
import context.dispatcher
eventBus.subscribe(context.self, MyTopics.FooTopic)
override def receive: Receive = {
case Foo(name: String) => {
dao.get(name)
.flatMap(result => dao2.getSomeMoreStuff(result)
.flatMap( data => //do more stuff)
)
}
}
}
When the actor finish to process Foo, it will invoke this future composition, and will move to process another Foo message, before this composition is finished, which is ok (I think).
My problem is testing this actor:
class MyActorTest(_system: ActorSystem) extends TestKit(_system)
with WordSpecLike with Matchers with BeforeAndAfterAll
with MockitoSugar with DefaultTimeout with ImplicitSender{
def this() = this(ActorSystem("myActorSpec"))
override def afterAll {
TestKit.shutdownActorSystem(system)
}
trait MyActorScope extends Scope {
val myDao = mock[MyDao]
val otherDao = mock[OtherDao]
val eventBus = new MyEventBus()
val myActor = TestActorRef(new MyActor(myDao, otherDao, eventBus)
}
"Test" must {
"verify dao" in new MyActorScope {
when(myDao.get(any)).thenReturn(Future.successful(("myDaoResult")))
when(otherDao.getSomeMoreStuff(any)).thenReturn(Future.successful(("otherDaoResult")))
eventBus.publish(new FooMessage(FooPayload("foo")))
verify(myDao).get(any)
verify(otherDao).getSomeMoreStuff(any)
}
}
}
So what happens here, is that myDao is verified successfully but the other Dao isn't.
I think it's because the composition of the futures did not happened before the end of this message processing.
Any way to handle this? Does the actor code make sense?
Thanks!
Fixed it with using Timeout VerificationMode
"Test" must {
"verify dao" in new MyActorScope {
when(myDao.get(any)).thenReturn(Future.successful(("myDaoResult")))
when(otherDao.getSomeMoreStuff(any)).thenReturn(Future.successful(("otherDaoResult")))
eventBus.publish(new FooMessage(FooPayload("foo")))
verify(myDao, new Timeout(500, times(1))).get(any)
verify(otherDao, new Timeout(500, times(1))).getSomeMoreStuff(any)
}
}
I need an actor to stop one of its children, so that I can possibly create a new actor with same name (UUID ?).
I've got an ActorSystem with one Actor child. And this child creates new actors with context.actorOf and context.watch. When I try to stop one of these using context.stop, I observe that its postStop method is called as expected, but no matter how long I wait (seconds... minutes...), it never sends back the Terminated message to its creator (and watching) actor.
I read this in the AKKA documentation:
Since stopping an actor is asynchronous, you cannot immediately reuse the name of the child you just stopped; this will result in an InvalidActorNameException. Instead, watch the terminating actor and create its replacement in response to the Terminated message which will eventually arrive.
I don't care waiting for normal termination, but I really need actors to eventually terminate when asked to. Am I missing something ? Should I create actors directly from the system instead of from an actor ?
EDIT:
Here is my code :
object MyApp extends App {
def start() = {
val system = ActorSystem("MySystem")
val supervisor = system.actorOf(Supervisor.props(), name = "Supervisor")
}
override def main(args: Array[String]) {
start()
}
}
object Supervisor {
def props(): Props = Props(new Supervisor())
}
case class Supervisor() extends Actor {
private var actor: ActorRef = null
start()
def newActor(name: String): ActorRef = {
try {
actor = context.actorOf(MyActor.props(name), name)
context.watch(actor)
} catch {
case iane: InvalidActorNameException =>
println(name + " not terminated yet.")
null
}
}
def terminateActor() {
if (actor != null) context.stop(actor)
actor = null
}
def start() {
while (true) {
// do something
terminateActor()
newActor("new name possibly same name as a previously terminated one")
Thread.sleep(5000)
}
}
override def receive = {
case Terminated(x) => println("Received termination confirmation: " + x)
case _ => println("Unexpected message.")
}
override def postStop = {
println("Supervisor called postStop().")
}
}
object MyActor {
def props(name: String): Props = Props(new MyActor(name))
}
case class MyActor(name: String) extends Actor {
run()
def run() = {
// do something
}
override def receive = {
case _ => ()
}
override def postStop {
println(name + " called postStop().")
}
}
EDIT²: As mentionned by #DanGetz, one shall not need to call Thread.sleep in an AKKA actor. Here what I needed was a periodical routine. This can be done using the AKKA context scheduler. See: http://doc.akka.io/docs/akka/2.3.3/scala/howto.html#scheduling-periodic-messages . Instead I was blocking the actor in an infinite loop, preventing it to use its asynchronous mecanisms (messages). I changed the title since the problem was actually not involving actor termination.
It's hard to gauge exactly what you want now that the question has changed a bit, but I'm going to take a stab anyway. Below you will find a modified version of your code that shows both periodic scheduling of a task (one that kicks off the child termination process) and also watching a child and only creating a new one with the same name when we are sure the previous one has stopped. If you run the code below, every 5 seconds you should see it kill the child and wait for the termination message before stating a new one with the exact same name. I hope this is what you were looking for:
object Supervisor {
val ChildName = "foo"
def props(): Props = Props(new Supervisor())
case class TerminateChild(name:String)
}
case class Supervisor() extends Actor {
import Supervisor._
import scala.concurrent.duration._
import context._
//Start child upon creation of this actor
newActor(ChildName)
override def preStart = {
//Schedule regular job to run every 5 seconds
context.system.scheduler.schedule(5 seconds, 5 seconds, self, TerminateChild(ChildName))
}
def newActor(name: String): ActorRef = {
val child = context.actorOf(MyActor.props(name), name)
watch(child)
println(s"created child for name $name")
child
}
def terminateActor(name:String) = context.child(ChildName).foreach{ ref =>
println(s"terminating child for name $name")
context stop ref
}
override def receive = {
case TerminateChild(name) =>
terminateActor(name)
case Terminated(x) =>
println("Received termination confirmation: " + x)
newActor(ChildName)
case _ => println("Unexpected message.")
}
override def postStop = {
println("Supervisor called postStop().")
}
}