I tried to implement a timer based on Scala's actors API with, the current Thread actor (Actor.self) as the timer and an anonymous Actor which does the work that needs to be completed in time.
I have the following Scala program
import scala.actors.Actor.self
import scala.actors.TIMEOUT
object Main {
def main(args: Array[String]): Unit = {
val thiz = self
actor {
// do heavy work here
thiz ! "finish"
}
self.reactWithin(1000) {
case "finish" => println("complete")
case TIMEOUT => println("timeout")
}
}
}
When I run the program, I received
Exception in thread "main" scala.actors.SuspendActorControl
scala.actors.ActorProxy#1d99a4d: caught java.lang.InterruptedException
Please show me the way to overcome the problem.
You have two types of control passing with scala-actors, thread-blocking or thread-suspension. the latter means a control exception is thrown (the thread is made available again to the thread pool manager), and the actor body re-executed when a message comes into its mailbox. See the actors tutorial for more details, esp. section "Make it Thread-less!".
The receiveWithin method uses the thread-blocking, and the reactWithin the suspension. The problem you have here is that there is no outer managing actor that catches the exception. This only works within a "proper" actor, not with the proxy created for the main thread. So if you want to wait on the main thread outside an explicit actor, you need to use thread blocking / receiveWithin:
self.receiveWithin(1000) { ... }
Related
I'm creating an actor per unit of work. Each actor creates a thread pool.
when the work is completed it messages its sender which will inturn send the child actor a poison pill
I noticed that the number of threads in the jvm process is still growing indefinitly even though the child actors are "killed"
Example
class ParentActor (...) extends Actor {
....
....
val childActor = props(...child actor props...)
val resultFuture = childActor ? "do some work"
...
resultFuture onComplete {
...
childActor ! PoisonPill // "kill" the child actor
}
class ChildActor(...) extends Actor {
val executionContext: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))
...
receive {
...
sender ! "done"
}
override def postStop() {
println("post stop called") // the actor prints this
}
}
Shouldn't the actor be GCd along with its threads?
Thread pools don't get automatically garbage collected. See the docs for the Java ThreadPoolExecutor
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ThreadPoolExecutor.html
A pool that is no longer referenced in a program AND has no remaining threads may be reclaimed (garbage collected) without being explicitly shutdown.
But since you are creating a fixed pool, it will never have "no remaining threads". So it will never be collected by the JVM, even though the child actor is stopped.
You could implement a cleanup method in a postStop, calling shutdownNow(). But, as Thilo points out, managing thread pools in child actors is pretty weird. You don't explain why you want to do that, but I'd consider letting Akka manage your threads.
I have an actor p: ParentActor which I want to do some cleanup jobs when it is stopped by making use of the postStop method. One of the jobs involves sending a message to a child actor c: ChildActor. After that, c and then p should be stopped. However, once context.stop(p) has been called c seems to be immediately stopped and is unable to receive messages.
Below is an example of what I'd like to do:
class ParentActor extends Actor {
...
override def postStop {
logger.info("Shutdown message received. Sending message to child...")
val future = c ? "doThing"
logger.info("Waiting for child to complete task...")
Await.result(future, Duration.Inf)
context.stop(c)
logger.info("Child stopped. Stopping self. Bye!")
context.stop(self)
}
}
Results in error message:
[ERROR] [SetSystem-akka.actor.default-dispatcher-5] [akka://SetSystem/user/ParentActor] Recipient[Actor[akka://SetSystem/user/ParentActor/ChildActor#70868360]] had already been terminated. Sender[Actor[akka://SetSystem/user/ParentActor#662624985]] sent the message of type "java.lang.String".
An alternative would be to send p a message saying to shutdown, and have the above actions take place as a result of that, but using the built in stopping functionality seems better.
PS. This is a new application so design alternatives are welcome.
When an actor A is stopped, its children are indeed stopped before A's postStop hook is called. The sequence of events when an actor is stopped is as follows (from the official documentation):
Termination of an actor proceeds in two steps: first the actor suspends its mailbox processing and sends a stop command to all its children, then it keeps processing the internal termination notifications from its children until the last one is gone, finally terminating itself (invoking postStop, dumping mailbox, publishing Terminated on the DeathWatch, telling its supervisor).
Overriding the parent's postStop won't help you because your desired shutdown procedure includes sending a message to a child and waiting for a reply. When the parent is terminated, the child is stopped before the parent's postStop is run.
As you mentioned, sending a specific message to the ParentActor to initiate the shutdown is another approach. Something like the following would work:
import akka.pattern.pipe
class ParentActor extends Actor {
...
def receive = {
case Shutdown =>
(c ? DoYourThing).mapTo[ThingIsDone].pipeTo(self)
case ThingIsDone =>
logger.info("Child has finished its task.")
context.stop(self)
case ...
}
}
Note that one should avoid using Await in an actor. Instead, pipe the result of a Future to an actor.
I have an actor that has a mutable state. In my receive method, I pattern match the messages and call some service that would return a Future. This Future would modify the state in my Actor instance. Is this state not thread safe? Since the Future would be executing in a different thread, is the state in my Actor this guaranteed to be thread safe?
No that will not be threadsafe as you correctly assumed. Futures run on any thread that the execution context provides.
The way to solve this is to pipe it back to the same actor. All actor's inputs must always be messages. You can find the documentation here.
Some example code:
import akka.pattern.pipe
//... inside the Actor somewhere:
val futureResult: Future[YourType] = something.thatReturnsAFuture()
futureResult.pipeTo(self)
And then amend your receive block so the result will be processed after the future completes and it is sent back to this actor:
case result: YourType => //...
I have a supervising Akka actor which uses a router to forward messages to worker actors.
I have a class which wraps the supervisor and when I call a method on that class it "asks" the supervisor to do something and then I use Await.result(theFuture) to wait for the result (I cannot continue without the result).
If the workers throw an exception, I want to restart the worker which threw the exception, and I want the exception to be caught by the code which calls the wrapper class.
I passed a OneForOneStrategy to the router constructor, which returns RESTART in the case of an Exception. In the postRestart method of the worker, I log the restart, so I can validate that the worker is actually restarted.
When the worker throws an exception, it gets restarted, but the exception disappears. The Future which is the result of asking the supervisor, contains an exception, but it is a akka.pattern.AskTimeoutException, which is thrown after just 5 seconds rather than 20 seconds, which is the implicit timeout that I have lingering around. The exception actually occurs less than a second after the worker starts.
Question 1: how can I get the exception from the worker in the code which calls my wrapper class?
Also, the receive method of the worker is like this:
def receive = {
case r: Request =>
val response = ??? //throws an exception sometimes
sender ! response
}
Something is logging the exception to the console, but it isn't my code. The stack trace is:
[ERROR] [02/11/2013 21:34:20.093] [MySystem-akka.actor.default-dispatcher-9]
[akka://MySystem/user/MySupervisor/MyRouter/$a] Something went wrong!
at myApp.Worker.$$anonfun$receive$1.applyOrElse(Source.scala:169)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:425)
at akka.actor.ActorCell.invoke(ActorCell.scala:386)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:230)
at akka.dispatch.Mailbox.run(Mailbox.scala:212)
at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:502)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
Line 169 of Source.scala is the line val response = ??? shown in the listing of the receive method above.
Question 2: who is logging that exception to the console, and how can I stop it?
1)
try somethingThatCanFail() catch {
case e: Exception => sender ! Status.Failure(e); throw e
}
The "tell failure" causes the caller to get a Failure containing the exception. Throwing "e" causes the oneForOneStrategy to be called which restarts the worker.
2)
It is the actor system itself that logs the failure, and the only way
to quiet it down is to filter out things by creating and configuring
your own LoggingAdapter as described here
http://doc.akka.io/docs/akka/2.1.0/scala/logging.html There is a
ticket for changing this
https://www.assembla.com/spaces/akka/tickets/2824 but it is targeted
for Akka 2.2
Answered by https://groups.google.com/forum/#!topic/akka-user/fenCvYu3HYE
In order to be notified of one of your children failing, you need to
First watch the child
Then you will be sent a Terminated() when the actor dies with a reference to it.
Something like:
class ParentActor extends Actor {
// this is sample of how to watch for death of one of your children
val childActor = context.actorOf(Props[SomeService], "SomeService")
val dyingChild = context.watch(context.actorOf(childActor))
def receive = {
case Terminated(`dyingChild`) =>
println("dyingChild died")
case Terminated(terminatedActor) =>
println(s"This child just died $terminatedActor")
}
}
Hope this helps.
In Java I have a hobby with thread, for example:
Thread thread = new Thread() {
#Override
public void run() {
//use this while loop, I can stop/ interrupt the thread when I want
while (!isInterrupted()) {
//...
}
}
};
thread.start();
and then, when I want to stop/ interrupt my thread:
thread.interrupt();
So my question is: is there a built-in way (a field/ method/ function...) in Scala that I can stop/ interrupt an actor?
This is my background: I'm new to Scala, I'm really learning to code. And I'm finding my best way between actor and thread. From my point of view, I like the new approach - actor.
P.S: Sorry for my English...
As indicated by the other answer, the actor model is specifically designed to restrict all interaction with an Actor to message passing and handling. Scala/Akka accomplish this by forcing you to create an Actor by calling the actorOf method. Since you don't have a reference to the underlying object, you can't call methods on it directly.
So, if you want to have an Actor that can be interrupted, just handle some message that does that.
def receive = {
case 'Interrupt => // handle interruption...
}
and in your client code
a ! 'Interrupt
You can send an Actor a PoisonPill to ask him to terminates (see http://akka.io/docs/akka/1.2/intro/getting-started-first-scala.html)
Please note that that works with akka Actors. Don't know for scala actors.