This earlier question suggests that calling 'stop' on a supervisor actor will shut down all linked actors. However, if one creates a 'custom' actor (not through a factory), it seems that this auto-shutdown doesn't happen. For example, see this code from the answer to another question:
class Module1 extends Actor {
self.faultHandler = OneForOneStrategy(List(classOf[Throwable]), 5, 5000)
def receive = {
case Register(actor) =>
self.link(actor)
}
}
If 'stop' was called on the above Module1 actor, the actors linked to it wouldn't shut down. Is there a way to make a custom actor automatically shut down linked actors? Or is this just something that you have to write yourself if you want to create a custom actor?
Thanks!
You can call:
self.linkedActors.values.iterator
and then send a PoisonPill or stop() them.
Related
I have got long running processes, let's say 2h to 1day. Each process starts its lifecycle with an update message and then continues to listen further concurrent updates. In the update message there is a unique target identifier.
If I want to represent each process with an Actor, how do I initialize the actor? I clearly need to do an atomic look-up/create operation based on the value of the identifier in the update message? How to do I design this with scala/akka?
Setup a single actor that performs the management of these process actors (say a ProcessManager actor). This actor will support requests to get a process actor for a particular process id. Internally, it will see if that child already exists or not. If it exists, it will respond to the sender with that ref. If not, it will create it and then respond to the sender with that ref. Because this manager actor processes it's mailbox serially (as all actors do), you don't have to worry about race conditions with the lookup/create. A very simplified example of this:
case class GetProcessHandler(processId:Int)
class ProcessManager extends Actor{
def receive = {
case GetProcessHandler(id) =>
val name = s"proc_$id"
val handler = context.child(name).getOrElse(
context.actorOf(Props[ProcessHandler], name)
)
sender ! handler
}
}
class ProcessHandler extends Actor{
def receive = {
...
}
}
You can specify your starting actors in your application.conf. And then your main program you can create/initialize these actors by using your ActorSystem.
I have a play application where I am using actors that are do some constant work / monitoring.
e.g.
class MyActor extends Actor {
def act() { while(true) { /* work */ } }
}
in my code I start this actor exactly once.
My problem is that whenever play automatically rebuilds the application (due to source changes), it will create a new Actor, but will not get rid of the old actor.
The exact same thing happens if using threads (including daemon threads) instead of actors for the monitoring.
Is there any way to kill the old actors / threads on an automatic rebuild, or alternatively ensure that only a single actor will exist (I've tried making the actor thread an object, but this didn't help anything), other than restarting the application manually (I'm fine automatically with restarting the application on every change)?
Also, is there a better pattern for background monitoring in play (obviously one which will not create non-ending threads).
Thanks
You can define a Global object to listen to application events (Which must be defined in the default package):
import play.api.GlobalSettings
object Global extends GlobalSettings {
override def onStart(application: play.api.Application) {
println("Starting actors")
MyActorSystem
}
override def onStop(application: play.api.Application) {
println("Stopping actors")
MyActorSystem.system.shutdown()
}
}
The stop and start events are triggered when reload happens.
If you are using Play's internal actor system I think you can use this instead:
play.api.libs.concurrent.Akka.system.shutdown()
I want to have the possibility to put actors to sleep for a while. The actors should decide themselves how long they are going to sleep. As Thread.sleep() is not a recommended way of doing this I thought of using the scheduler in akka. I therefore defined an actor were another actor can register for being woken up.
class Scheduler extends Actor {
def receive = {
case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
sender ! Ring
}
}
}
But the sending actor never receives the Ring message.
So my questions are
Is scheduling with the scheduler recommended inside an actor?
Why is the sending actor never receiving the Ring message?
If this is not possible what is the recommended way of solving the problem?
Let me first answer the title question: yes, it is possible to use the scheduler inside an actor.
case Sleep(duration) =>
context.system.scheduler.scheduleOnce(duration, self, Ring)
Now to the question behind the question
You did not say what you actually want to achieve, so I’m making an educated guess here that you want the actor—which normally does something called “X”—to do something called “Y” for a while, suspending the “X” activity. The full solutions to this would be
class Sleepy extends Actor {
def receive = {
... // cases doing “X”
case Sleep(duration) =>
case object WakeUp
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
context.become({
case WakeUp => context.unbecome()
// drop the rest
}, discardOld = false)
}
}
The same could as well be implemented using the FSM trait and switching between the normal and the sleeping state. And of course you can do whatever you want while sleeping, e.g. mix in the Stash trait in Akka 2.1 and call stash() for all (or some) messages while sleeping, unstashAll() when getting the WakeUp message; or you could do something else altogether. Actors are very flexible.
What actors don’t do
Actors never really sleep, they always handle incoming messages. As shown above, you can define what that means, but the basic principle is that you cannot suspend an actor such that it will not process the messages in its mailbox.
You are closing over "sender" in your closure that's passed to the scheduler. This means that the Ring message is most likely being sent to the wrong actor. You should do this instead:
case Sleep(duration) =>
val s = sender
context.system.scheduler.scheduleOnce(duration) {
s ! Ring
}
}
Roland Kuhn's answer covers the subject, I just wanted to add that there's another common use-case for using the scheduler:
when sending a message to a different actor and waiting for this actor to respond, it's quite common to cap the wait with a timeout.
otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self
I'm using Akka Actors and I'm trying to update my code to use the latest 2.0 milestone. The API changed somewhat, for example the creation of Actors now works via something called an ActorSystem.
Starting and stopping actors changed as well - the latter is available via the ActorSystems methods .stop(..) and .shutdown(). But I can for the life of me not figure out how to start them...
The documentation is good, but seems to be missing some important points. I feel kinda stupid to ask, but how do you start actors in your Akka 2.0 environment? If I understood correctly actors who have a 'parent' are started when this parent is started - but what about the top level actor(s)?
In Akka 2.0, there is no need for a start() method because Actors are started as soon as you instantiate them in the context of an ActorSystem (or another Actor) -- but you need to instantiate them with one of the provided methods of ActorSystem or an Actor's context.
So, for example, if you have an Actor subclass called MyClass, you could start it with:
val system = ActorSystem()
val myActor = system.actorOf(Props[MyActor])
or, if your actor took constructor arguments:
val myActor = system.actorOf(Props(new MyActor("arg1"))
or, if you were in the body of another Actor,
val myActor = context.actorOf(Props(new Actor("arg1"))
and then your actor could immediately receive messages, e.g.
myActor ! MyMessage
Even your top level actors are started immediately, as all Actors in 2.0 are automatically in a supervision hierarchy. As soon as the actor is instantiated with the ActorSystem, it's ready to receive messages.
Scenario: I have this code:
class MyActor extends Actor {
def act() {
react {
case Message() => println("hi")
}
}
}
def meth() {
val a = new MyActor
a.start
a ! Message()
}
is the MyActor instance garbage collected? if not, how do i make sure it is? if I create an ad-hoc actor (with the 'actor' method), is that actor GCed?
This thread on the scala-user mailing list is relevant.
There Phillip Haller mentions using a particular scheduler (available in Scala 2.8) to enable termination of an Actor before garbage collection, either on a global or per-actor basis.
Memory leaks with the standard Actor library has lead to other Actor implementations. This was the reason for David Pollak and Jonas Boner's Actor library for Lift that you can read much more about here: http://blog.lostlake.org/index.php?/archives/96-Migrating-from-Scala-Actors-to-Lift-Actors.html
Have you tried adding a finalize method to see whether it is? I think the answer here is that the actors subsystem behaves no different to how you would expect it to: it does not cache any reference to your actor except in a thread-local for the duration of processing.
I would therefore expect that your actor is a candidate for collection (assuming the subsystem correctly clears out the ThreadLocal reference after the actor has processed the message which it does indeed appear to do in the Reaction.run method).