I have seen quite a few syntaxes for creating an Actor:
system.actorOf(Props(new A(a, b)), "name")
system.actorOf(Props(classOf[A], a, b), "name")
system.actorOf(Props[A], "name")
system.actorOf(A(a).props(), "name")
When should one use each of these?
If there are more, additions are welcome.
I prefer construction with companion object like:
object MyActor {
def props(): Props = Props[ClientActor]
}
class MyActor extends Actor {
def receive: Receive = {
...
}
}
If you need some parameters put to the actor you can use:
object MyActorHandler {
def props(parameter: String, address: SocketAddress): Props =
Props(classOf[ClientActorHandler], parameter, address)
}
class MyActorHandler(parameter: String, address: SocketAddress)
extends Actor {
def receive: Receive = {
...
}
}
When you add more parameter to the Actor constructor you have all in one place.
Second suggestion: create actor by context.actorOf() from supervisor. Create actor hierarchy.For more details see Supervision and Monitoring
Related
I am trying some example in Play Framework (Scala). I'm injecting an actor into controller.
Configuration
Java (1.8.0_144)
Scala (2.12.3)
Play (2.6.5)
I have following code:
ExampleController
class ExampleController #Inject() (
controllerComponents: ControllerComponents,
#Named("injected-router") injectedRouterActor: ActorRef,
#Named("injected") injectedActor: ActorRef)
extends AbstractController(controllerComponents) {
def alive = Action {
injectedActor ! "Hi from Example"
injectedRouterActor ! "Hi From Example to Router"
Ok("Alive")
}
}
InjectedActor
class InjectedActor extends Actor {
val name = s"IA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
InjectedRouterActor
class InjectedRouterActor extends Actor {
val name = s"IRA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
ChildActor
class ChildActor extends Actor {
val name = s"CH-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
}
Module
class BindingModule extends AbstractModule with AkkaGuiceSupport {
def configure = {
bindActor[InjectedActor]("injected")
bindActor[InjectedRouterActor]("injected-router", _ => RoundRobinPool(5).props(Props[ChildActor]))
}
}
When I run this, and hit route for alive, I see printlns from all actors visible on console, except for InjectedRouterActor.
Unable to understand why? Any help is appreciated.
Thanks
In Akka routers are special implementation actors that you don't explicitly implement.
In your example RoundRobinPool(5).props(Props[ChildActor]) creates Props that would create round robin pool router with routees being actors of type ChildActor. You don't really need InjectedRouterActor. You might still want to have it if you want to create router based on configuration (see examples in Akka docs).
If you look at the source of ActorRefProvider that creates actors when you use Guice helper
class ActorRefProvider[T <: Actor: ClassTag](name: String, props: Props => Props) extends Provider[ActorRef] {
#Inject private var actorSystem: ActorSystem = _
#Inject private var injector: Injector = _
lazy val get = {
val creation = Props(injector.instanceOf[T])
actorSystem.actorOf(props(creation), name)
}
}
you can see that it creates default Props that gets an instance of InjectedRouterActor (the type informations is passed as T type parameter) from the injector but, since you provide props as a function where the function argument is ignored (_ => RoundRobinPool(5).props(Props[ChildActor])), it will just ignore creation variable. Also injector.instanceOf[T] is passed to Props#apply as by-name parameter so it is not called right away, so your InjectedRouterActor is not created.
Instead of creating binding for the router actor in configure you can create it manually:
#Provides
#Named("injected-router")
#Singleton
def routerProvider(system: ActorSystem): ActorRef = {
system.actorOf(RoundRobinPool(5).props(Props[ChildActor]), name = "injected-router")
}
I would like to implement a little HTTP Server with Scala and Akka. Specifically, I want to have two kind of actor: EmployeeRouterActor and EmployeeEchoActor.
The fisrt one, I want to use it like a router, I mean, that actor receive all messages and it must create an child (in this case, EmployeeEchoActor) for each message.
Each child, it will receive an Employee message and it must give back a string with the employee information.
Moreover, after child complete its process, the child must die. I think the parent is who has to control lifecycle of their children.
In Akka documentation, I only see about using a single child, like this
How can I do this? Is there any example or any other documentation from Akka site?
Something like this:
object EmployeeRouterActor {
final case class Employee(id: String, name: String)
final case object StopChild
final case class ChildResponse(id: String, data: String)
}
final class EmployeeRouterActor extends Actor {
import EmployeeRouterActor._
// Make a map which will store child actors
private var children = Map.empty[String, ActorRef]
override def receive: Receive = {
case e # Employee(id, _) => getChild(id) ! e
case ChildResponse(id, _) => stopChild(id)
}
// Check whether child exists in context of this actor.
// If it doesn't, create new one.
private def getChild(id: String): ActorRef =
context.child(id).getOrElse {
val child = context.actorOf(EmployeeEchoActor.apply(), id)
children += (id -> child)
child
}
private def stopChild(id: String) = {
children(id) ! StopChild
children -= id
}
}
object EmployeeEchoActor {
def apply(): Props = Props(new EmployeeEchoActor)
}
final class EmployeeEchoActor extends Actor {
// self.path.name to access its id
override def receive: Receive = {
case EmployeeRouterActor.Employee =>
// do stuff with Employee message...
context.parent ! EmployeeRouterActor.ChildResponse(self.path.name, "Done!") // Or pipeTo(context.parent)
case EmployeeRouterActor.StopChild => context.stop(self)
}
}
Basically, child actors are created and stored in a Map. When they finish their tasks, they reply with the response message to their parent which then stops them.
According to the Play documentation on WebSockets the standard way to establish a WebSocket is to use ActorFlow.actorRef, which takes a function returning the Props of my actor. My goal is to get a reference to this underlying ActorRef, for instance in order to send a first message or to pass the ActorRef to another actor's constructor.
In terms of the minimal example from the documentation, I'm trying to achieve this:
class WebSocketController #Inject() (implicit system: ActorSystem, materializer: Materializer) {
def socket = WebSocket.accept[String, String] { request =>
val flow = ActorFlow.actorRef { out => MyWebSocketActor.props(out) }
// How to get the ActorRef that is created by MyWebSocketActor.props(out)?
// Fictitious syntax (does not work)
flow.underlyingActor ! "first message send"
flow
}
}
How can I get a reference to the actor that is created?
If it is not possible to get an ActorRef at this point (does it require materialization of the flow?), what would be the easiest way to store a reference to the created actor?
Using Actor.preStart() hook you can do some tricks to access the actorRef:
class MyWebSocketActor(
out: ActorRef,
firstMessage: Any,
actorRegistry: ActorRef
) extends Actor {
import play.api.libs.json.JsValue
override def preStart(): Unit = {
self ! firstMessage
actorRegistry ! self
}
...
}
def socket = WebSocket.accept[String, String] { request =>
ActorFlow.actorRef { out =>
Props(new MyWebSocketActor(out, "First Message", someRegistryActorRef))
}
}
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
}
Recently I was switching from scala actors to akka actors, but noticed that akka actors use ActorRef instead of the instance object:
val actorRef: ActorRef = Actor.actorOf(new MyActor)
So I tried:
val myActor = new MyActor
val actorRef: ActorRef = Actor.actorOf(x)
... to have both: 1) ActorRef to send messages and 2) MyActor to call methods on.
But I got:
akka.actor.ActorInitializationException: ActorRef for instance of actor [MyActor] is not in scope.
So my question is: How can I obtain an instance (of some type) on which I can call ActorRef-like methods like ! AND also methods from the MyActor instance?
What you're doing is a terrible idea. So just stop right now, step away from the keyboard, and go to the Akka Documentation and read up on Actors.
Consider this:
class YourActor extends Actor {
var mutableStuff = ...
def receive = {
case _ =>
// mess with mutableStuff
}
def publicMethod = // mess with mutableStuff
}
Now, set up your system and start sending messages and calling that method from other threads. Boom!
You're doing precisely what Akka and the Actor model help you prevent. You're actually bending over backwards to break what they've already fixed :) They won't let you do it.
Now, you can unit test by accessing methods directly but you need a TestActorRef for that. While you're reading the docs, read through the section on Testing.
The best that I can up with is the following, quite dirty:
Is there a better way?
import akka.actor._
trait ActorCom {
var actorRefForInitialization: ActorRef = _
lazy val actorRef: ActorRef = actorRefForInitialization
def ?(message: Any)(implicit channel: UntypedChannel = NullChannel, timeout: Actor.Timeout = Actor.defaultTimeout) = actorRef ? message
def !(msg: Any)(implicit sender: UntypedChannel) = actorRef ! msg
def start = actorRef.start
}
object AkkaActorFactory {
def apply[A <: Actor](newInstance: => A with ActorCom): A with ActorCom = {
var instance: Option[A with ActorCom] = None
val actorRef = Actor.actorOf({
instance = Some(newInstance)
instance.get
})
instance.get.actorRefForInitialization = actorRef
instance.get.actorRef // touch lazy val in ActorCom, to make it equal to actorRef and then its fixed (immutable)
instance.get
}
}
class MyActor extends Actor {
def receive = {
case "test1" => println("good")
case "test2" => println("fine")
case _ => println("bad")
}
def sendTestMsg2Myself = self ! "test2"
}
val myActor = AkkaActorFactory(newInstance = new MyActor with ActorCom)
myActor.start
myActor ! "test1"
myActor.sendTestMsg2Myself // example for calling methods on MyActor-instance
myActor ! PoisonPill