If I have an actor that sends messages to another actor, should I be obtaining a reference to that actor (e.g. context.actorSelection(somePath)) every time I want to send a message to it or can I do it once when my actor is initialized and then reuse the ActorRef?
I think a distinction needs to be made between an actor failing and being restarted by it's supervisor and an actor being explicitly stopped. If you had an ActorRef that you had obtained in some way or another (looked it up and resolved it via ActorSelection or just happened to have it from when it was created) and the underlying actor instance fails and is restarted by its supervisor, then that ActorRef will still work just fine. Even though the actor technically stops during the fail and restart (postStop will be called), it's name is never released and any refs that referred to it will still be valid.
Now, if you explicitly stopped that actor, and then later started up a new one with the same name (and thus same path), ActorRefs that referred to it pre stoping will not work. The actor instance that they referred to was stopped and thus these refs are invalid even though later a new instance was started with the same name and thus same path.
Lastly, you can use ActorSelections to get around the issue described in the above paragraph. If you keep the result of .actorSelection as an ActorSelection and do not resolve it into a single ActorRef, then you will continue to be able to send messages through it (ActorSelection supports tell/!) and to an actor represented by it even if the first instance is initially stopped and a new instance for the same name is started later.
You can reuse ActorRefs, that's what they're meant for.
http://doc.akka.io/docs/akka/2.3.7/general/addressing.html
Related
I'm new to the Akka framework and I'm building a group chat application with it. My application may have 10 million actor instances (an actor instance for each group chat) of the same type, only 5% of which are highly active, and 60% of which can be idle (not receiving any messages) for days.
I want to know:
Is there any best practice to identify these idle actors?
What is the best practice to deal with them? Is stopping them enough?
Is there any best practice to identify these idle actors?
An actor's ActorContext has a setReceiveTimeout method that defines an inactivity threshold for the actor: if the actor hasn't received a message in the given amount of time, then an akka.actor.ReceiveTimeout message is sent to the actor. For example:
import akka.actor.{ Actor, ReceiveTimeout }
import scala.concurrent.duration._
class ChatActor extends Actor {
context.setReceiveTimeout(2 hours)
def receive = {
case ReceiveTimeout =>
// do something
// other case clauses
}
}
The above ChatActor will receive a ReceiveTimeout message if it hasn't received a message for two hours. (However, as the documentation states: "the receive timeout might fire and enqueue the ReceiveTimeout message right after another message was enqueued; hence it is not guaranteed that upon reception of the receive timeout there must have been an idle period beforehand as configured via this method.")
What is the best practice to deal with them?
It's a good idea to stop inactive actors; otherwise you could have a memory leak. Here are a few approaches for stopping these actors:
The inactive actor throws an exception, which is handled in a supervisor strategy defined in the actor's parent. In the supervisor strategy, the parent stops the idle actor (e.g., via context stop sender()).
The inactive actor sends its self reference to a "reaper" actor that collects references to idle actors and culls (i.e., stops) these actors on a periodic basis (perhaps using a scheduler).
The inactive actor stops itself (via context stop self).
More information about stopping actors is found here.
Is stopping them enough?
When an actor is stopped, its ActorRef essentially becomes invalid. From the documentation:
After stopping an actor, its postStop hook is called, which may be used e.g. for deregistering this actor from other services. This hook is guaranteed to run after message queuing has been disabled for this actor, i.e. messages sent to a stopped actor will be redirected to the deadLetters of the ActorSystem.
At this point, the underlying actor instance to which the now-stale ActorRef points is eligible for garbage collection. In other words, an actor must be stopped in order for it to be eligible for garbage collection. Therefore, in regard to freeing up memory, stopping the actor is enough. You could also remove the invalid ActorRef itself after the actor has been stopped. Note that removing an ActorRef does not automatically stop the actor:
It is important to note that Actors do not stop automatically when no longer referenced, every Actor that is created must also explicitly be destroyed.
Is there any best practice to identify these idle actors?
The only way is to make each actor to keep the time when it was active last time. Then, to speedup investigation of the longest inactive actor, you can organize an index-like structure, e.g. PriorityQueue. Then a dedicated actor periodically awakes and cleans that structure from actors which are idle longer than some predefined period of time.
What is the best practice to deal with them? Is stopping them enough?
An idle actor does not consume any resources except core memory. If you have plenty of memory, the best practice is to do nothing. If you want to save that memory, store actor in database (after some period of inactivity), and then read it from there by demand.
I have an ActorSystem(e.g. A) which spawns other ActorSystem (e.g B). When B comes up, it knows the address of A and he executes cluster.join(). Once, the cluster is joined, actors can communicate with each other.
In my scenario:
I have a REST request coming to Spray framework to spawn a new
ActorSystem.
In the request handler, I do an ask(?) to ActorSystem A
"A" receives the message, I store the Address of ask(?) request to DB. It is a temp actor something like "akka://ActorSystemA/temp/$a"
"A" spawns a new JVM with ActorSystem "B"
As soon as "B" comes up and "A" gets a MemberUp message. I pick the ask temporary actorRef from DB and try to send a response back using something like
context.actorSelection("akka://ActorSystemA/temp/$a").resolveOne(3.seconds) ! Success
but it doesn't work. It always timesout
I tried adding a watch on the temp actor. The actor is not terminated, yet I cannot communicate.
Is this approach correct? Also, why I am getting timeout always.
It turns out that storing temporary references is a bad idea. You should never do it. I changed my design to get around this problem.
I have an Actor that I create from with another Actor (parent). I also spawn several other Actor's from within the parent. The tree looks like:
ParentActor
-- ServiceActor
-- ProcessActor1
-- ProcessActor2
Now I want to pass around this ServiceActor instance to ProcessActor instances, but the problem is that the ServiceActor could choke and be killed at some point. I handle this in my parent and I would have a Restart policy for the ServiceActor.
Now my question is say if I create all my Actors as mentioned above and after a couple of hours the ServiceActor gets Restarted because of an Exception happening, should I re-instantiate my ProcessActor's?
Is the old ServiceActor ActorRef reference still valid?
An ActorRef is valid even if the underlying actor is restarted multiple times. From the official documentation:
The rich lifecycle hooks of Actors provide a useful toolkit to implement various initialization patterns. During the lifetime of an ActorRef, an actor can potentially go through several restarts, where the old instance is replaced by a fresh one, invisibly to the outside observer who only sees the ActorRef.
I have written some actor classes and I find that I have to get a handle into the lifecycle of these entities. For example whenever my actor is initialized I would like a method to be called so that I can setup some listeners on message queues (or open db connections etc).
Is there an equivalent of this? The equivalent I can think of is Spring's InitialisingBean and DisposableBean
This is a typical scenario where you would override methods like preStart(), postStop(), etc. I don't see anything wrong with this.
Of course you have to be aware of the details - for example postStop() is called asynchronously after actor.stop() is invoked while preStart() is called when an Actor is started. This means that potentially slow/blocking things like DB interaction should be kept to a minimum.
You can also use the Actor's constructor for initialization of data.
As Matthew mentioned, supervision plays a big part in Akka - so you can instruct the supervisor to perform specific stuff on events. For example the so-called DeathWatch - you can be notified if one of the actors "you are watching upon" dies:
context.watch(child)
...
def receive = {
case Terminated(`child`) => lastSender ! "finished"
}
An Actor is basically two methods -- a constructor, and onMessage(Object): void.
There's nothing in its lifecycle that naturally provides for "wiring" behavior, which leaves you with a few options.
Use a Supervisor actor to create your other actors. A Supervisor is responsible for watching, starting and restarting Actors on failure -- and therefore it is often valuable to have a Supervisor that understands the state of integrated systems to avoid continously restarting. This Supervisor would create and manage Service objects (possibly via Spring) and pass them to Actors.
Use your preferred Initialization technique at the time of Actor construction. It's tricky but you can certainly combine Spring with Actors. Just be aware that should a Supervisor restart your actor, you'll need to be able to resurrect its desired state from whatever content you placed in the Props object you used to start it in the first place.
Wire everything on-demand. Open connections on demand when an Actor starts (and cache them as necessary). I find I do this fairly often -- and I let the Actor fail when its connections no longer work. The supervisor will restart the Actor, which will recreate all connections.
Something important things to remember:
The intent of Actor model is that Actors don't run continuously -- they only run when there are messages provided to them. If you add a message listener to an Actor, you are essentially adding new threads that can access that actor. This can be a problem if you use supervision -- a restarted actor may leak that thread and this may in turn cause the actor not to be garbage collected. It can also be a problem because it introduces a race condition, and part of the value of actors is avoiding that.
An Actor that does I/O is, from the perspective of the actor system, blocking. If you have too many Actors doing I/O at the same time, you will exhaust your Dispatcher's thread pool and lock up the system.
A given Actor instance can operate on many different threads over its lifetime, but will only operate on one thread at a time. This can be confusing to some messaging systems -- for example, JMS' Spec asserts that a Session not be used on multiple threads, and many JMS interpret this as "can only run on the thread on which it was started." You may see warnings, or even exceptions, resulting from this.
For these reasons, I prefer to use non-actor code to do some of my I/O. For example, I'll have an incoming message listener object whose responsibility is to take JMS messages off a queue, use them to create POJO messages, and send tells to the Actor system. Alternately, I'll use an Actor, but place that actor on a custom Dispatcher that has thread pinning enabled. This assures that that Actor will only run on a specific thread and won't block up the system that other non-I/O actors are using.
What is actually an Actor in context of code. Is it the java class which extends UnTypedActor ? i.e. 1 Actor=1 Class.
If yes, do we have multiple instance of it, simple referred using actorref. How does multiple instance of actorref for same actor differs from each other ?
What do we mean by actor failing or restart of an actor ? Do we just reload the class with last persisted data variables ?
Actor's behavior is represented by its class in code.
in runtime one logical actor has one (but not always same) instance in the system (there might be more in memory before GC).
One class may correspond to several logical actors - each has different address.
Actor instance is an instance of UntypedActor (or just Actor in scala) adressed in Actors system.
ActorRef is reference to the one (local or remote), but not always same instance (it's changing when actor is restarting), e.g. to the one logical Actor with its own address.
Failing is, simply saying, throwing an exception from onReceive (receive in Scala) method. When actor fails it sends Terminated message to its supervisor and (depending on SupervisorStrategy) may restart or stop. Restarting means:
calling preRestart method of actor's instance
creating new instance (which will be referenced from the same ActorRef after re-creation)
calling postRestart method of newely created instance. Actor's state is becoming lost after preRestart.