I read in the Akka docs that it's dangerous to close over variables from an enclosing actor.
Warning
In this case you need to carefully avoid closing over the
containing actor’s reference, i.e. do not call methods on the
enclosing actor from within the anonymous Actor class. This would
break the actor encapsulation and may introduce synchronization bugs
and race conditions because the other actor’s code will be scheduled
concurrently to the enclosing actor.
Now, I have two actors, one of which requests something from the second and does something with the result. In this example below I have put together, actor Accumulator retrieves numbers from actor NumberGenerator and adds them up, reporting the sum along the way.
This can be done in at least two different ways as this example shows with two different receive functions (A vs B). The difference between the two is that A does not close over the counter variable; instead it awaits an integer and sums it up, while B creates a Future that closes over counter and does the sum. This happens within an anonymous actor created just to process onSuccess, if I understand properly how this works.
import com.esotericsoftware.minlog.Log
import akka.actor.{Actor, Props}
import akka.pattern.{ask, pipe}
import akka.util.Timeout
import akka.util.duration._
case object Start
case object Request
object ActorTest {
var wake = 0
val accRef = Main.actorSystem.actorOf(Props[Accumulator], name = "accumulator")
val genRef = Main.actorSystem.actorOf(Props[NumberGenerator], name = "generator")
Log.info("ActorTest", "Starting !")
accRef ! Start
}
class Accumulator extends Actor {
var counter = 0
implicit val timeout = Timeout(5 seconds)
// A: WITHOUT CLOSURE
def receive = {
case Start => ask(ActorTest.genRef, Request).mapTo[Int] pipeTo self
case x: Int => counter += x; Log.info("Accumulator", "counter = " + counter); self ! Start
}
// B: WITH CLOSURE
def receive = {
case Start => ask(ActorTest.genRef, Request).mapTo[Int] onSuccess {
case x: Int => counter += x; Log.info("Accumulator", "counter = " + counter); self ! Start
}
}
}
class NumberGenerator extends Actor {
val rand = new java.util.Random()
def receive = {
case Request => sender ! rand.nextInt(11)-5
}
}
Is it absolutely evil to use closures in this case ? Of course I could use an AtomicInteger instead of an Int, or in some networking scenario using, say, netty, issue a write operation on a threadsafe channel, but this is not my point here.
To the risk of asking the ridiculous: is there a way for the Future's onSuccess to execute in this actor instead of an anonymous middle actor, without defining a case in the receive function ?
EDIT
To put it more clearly, my question is: Is there a way to force a series of Futures to run in the same thread as a given Actor ?
The problem is that the onSuccess is going to run in a different thread than the thread the actor's receive is going to run in. You could use the pipeTo approach, or use an Agent. Making counter an AtomicInteger would solve the problem, but it's not so clean - that is, it breaks the Actor model.
The easiest way of implementing such design is by using "fire-and-forget" semantic:
class Accumulator extends Actor {
private[this] var counter = 0
def receive = {
case Start => ActorTest.genRef ! Request
case x: Int => {
counter += x
Log.info("Accumulator", "counter = " + counter)
self ! Start
}
}
}
This solution is fully asynchronous, and you don't need any timeout.
Related
In Akka Cookbook by Héctor Veiga Ortiz, the reader is told that
When an actor throws an exception, it sends a message to the supervisor, and the supervisor handles the failure by restarting that actor. It clears out the accumulated state of the actor, and creates a fresh new actor, means, it then restores the last value assigned to the state of old actor to the preRestart value.
However, I tried testing the following code, which suggests that what the author says isn't true.
import akka.actor._
import akka.actor.SupervisorStrategy._
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.pattern.ask
case object Error
case class StopActor(actorRef: ActorRef)
case object Inc
class LifeCycleActor extends Actor {
var sum = 1
override def preRestart(reason: Throwable, message: Option[Any]):Unit =
println(s"sum in preRestart is $sum")
override def preStart(): Unit = println(s"sum in preStart is $sum")
def receive = {
case Inc => sum += 1
case Error => throw new ArithmeticException()
case _ => println("default msg")
}
override def postStop(): Unit =
println(s"sum in postStop is ${sum * 3}")
override def postRestart(reason: Throwable): Unit = {
sum = sum * 2
println(s"sum in postRestart is $sum")
}
}
class Supervisor extends Actor {
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute){
case _: ArithmeticException => Restart
case t =>
super.supervisorStrategy.decider.applyOrElse(t, (_:Any)=>Escalate)
}
def receive = {
case (props: Props, name: String) => sender ! context.actorOf(props, name)
case StopActor(actorRef) => context.stop(actorRef)
}
}
object ActorLifeCycle extends App {
implicit val timeout = Timeout(2 seconds)
val actorSystem = ActorSystem("Supervision")
val supervisor = actorSystem.actorOf(Props[Supervisor], "supervisor")
val childFuture = supervisor ? (Props(new LifeCycleActor), "LifeCycleActor")
val child = Await.result(childFuture.mapTo[ActorRef], 2 seconds)
child ! Inc
child ! Error
Thread.sleep(1000)
supervisor ! StopActor(child)
}
The output I get is as follows.
sbt:chpt2_ActorLifeCycle> runMain ActorLifeCycle
sum in preStart is 1
sum in preRestart is 2
[ERROR] [11/08/2018 20:06:01.423]
[Supervision-akka.actor.default-dispatcher-4]
[akka://Supervision/user/supervisor/LifeCycleActor] null
java.lang.ArithmeticException
sum in postRestart is 2
sum in postStop is 6
If what the author says is true, the final value should be double what it is.
First I guess you forget to add sum += 1 when receive message Inc in child actor when post the question, please modify. Otherwise, as I test, you cannot get your output.
Next explain your code:
From next diagram, you can see the preReStart is called on old instance, not on new instance.
There is also a desc about this, detail here
The old actor is informed by calling preRestart with the exception which caused the restart and the message which triggered that exception; the latter may be None if the restart was not caused by processing a message, e.g. when a supervisor does not trap the exception and is restarted in turn by its supervisor, or if an actor is restarted due to a sibling’s failure. If the message is available, then that message’s sender is also accessible in the usual way (i.e. by calling sender). This method is the best place for cleaning up, preparing hand-over to the fresh actor instance, etc. By default it stops all children and calls postStop.
The initial factory from the actorOf call is used to produce the fresh instance.
The new actor’s postRestart method is invoked with the exception which caused the restart. By default the preStart is called, just as in the normal start-up case.
So, for your example:
when call preRestart, it print the sum of old actor, that is 2, notice: you have inc it.
when call postRestart, it print the sum of new actor, that is the initial value 1 with the calculation sum = sum * 2, finally print 2, not 4. The Inc message just receive on old instance, not on new instance.
Finally, the content of the book:
When an actor throws an exception, it sends a message to the supervisor, and the supervisor handles the failure by restarting that actor. It clears out the accumulated state of the actor, and creates a fresh new actor, means, it then restores the last value assigned to the state of old actor to the preRestart value.
I think what you concern is it then restores the last value assigned to the state of old actor to the preRestart value. I don't quite know what it means, if you just think it assign the last value of old actor to preRestart function, then it is correct, as it just run on old instance, otherwise, it seems conflict with akka official guide & experiment; And, if want to restore the value, we may had to use resume not restart.
Anyway, I think we should use the akka offical document as a standard, and understand the correct logic.
I use IntelliJ IDEA, but the question could relate to other IDEs. There is a great way to navigate the code with Ctrl+click. From the method call it jumps to the method declaration. It really boosts the productivity.
Actor systems are based on message passing. Example in Akka with Scala:
class MyMessage
object MyMessage
class MyActor1 extends Actor {
context.actorOf(Props[MyActor2]) ! MyMessage
}
class MyActor2 extends Actor {
def receive = {
case MyMessage =>
...
}
}
Is there a way to navigate in code between sending the message and receiving the message?
I mean clicking on ! will take me to the definition of ! method in ScalaActorRef, but that's 99% chance that I don't want that. Jumping to the corresponding receive method (or, if possible, to correct case: case MyMessage) would be more appropriate.
How do you navigate the code between actors?
I don't think it is possible in general because an actor can change its behavior at runtime, including what messages it can process - as opposed to methods which can be statically indexed. For example, receive function may be computed depending on the actor state:
class MyActor extends Actor {
var i = 0
def receive = firstReceive
def commonReceive = {
case Increment =>
i += 1
if (i % 3 == 0) context.become(firstReceive)
else context.become(secondReceive)
}
def firstReceive = commonReceive orElse {
case Ping =>
sender ! "zero"
}
def secondReceive = commonReceive orElse {
case Ping =>
sender ! "one or two"
}
}
Now the actor handles messages differently depending on which messages it handled before. And this is only a simple example - actual actor behavior may even be received from the outside!
case class Behavior(receive: Actor.Receive)
class MyActor extends Actor {
def receive = {
case Behavior(r) => context.become(r)
}
}
Another difficulty which is even greater is that you usually have an ActorRef to which you send messages with !. This ActorRef has no static connection with the actor class which contains message handling logic - it is instantiated with Props which can use arbitrary code to determine which actor class should be used:
val r = new Random
val a = actorSystem.actorOf(Props(if (r.nextInt(100) > 50) new FirstActor else new SecondActor))
a ! Message // which handler should this declaration lead to?
This makes finding actual message handler next to impossible.
If you think that it may be worth it to support simpler cases, like the one you provided, you can always submit a feature request to YouTrack.
Not perfect, but what could help would be to use Find Usage (Alt+F7) on the type of the message. For that you probably have to navigate to the type Declaration (Ctrl+Shift+B) first
I wonder if there is an easy way to create a shortcut for the combination.
Another idea would be to use the Structural Search which might be able to find things like excpressions, that match on the class name ...
Once you created a template to your liking you can then record a macro
I have a function which uses scheduleOnce to schedule an event to happen some time in the future, and I want to write a test that checks that:
the event was indeed scheduled
it was scheduled at the correct time
the system behaves as expected when that event eventually triggers
but I don't want the test to actually wait several minutes doing nothing.
How should I best test code that uses akka's Scheduler?
Here is an example of mocking out the scheduler as described by #lmm. In this example, we really test the full scheduling and handling of the action as two separate scenarios. The first testing that given some condition (a message of a certain type being received in my example) we will schedule a callback, and the second being the handling of the message that gets fired back to self when that timer goes off. The code is as follows:
object TimerExampleActor{
case object ClearState
case class ScheduleStateClearing(duration:FiniteDuration)
}
class TimerExampleActor extends Actor{
import TimerExampleActor._
var state:List[Int] = Nil
def receive = {
case ScheduleStateClearing(d) =>
scheduler.scheduleOnce(d, self, ClearState)(context.dispatcher)
case ClearState =>
state = Nil
}
def scheduler = context.system.scheduler
}
Then, using specs2 and mockito, my test case is as follows:
class TimerExampleActorTest extends Specification with Mockito with NoTimeConversions{
import TimerExampleActor._
implicit val system = ActorSystem("test")
trait testscope extends Scope{
val mockScheduler = mock[Scheduler]
val actor = TestActorRef(new TimerExampleActor{
override def scheduler = mockScheduler
})
}
"A request to schedule state clearing" should{
"schedule a callback for the message ClearState to self with the supplied duration" in new testscope{
val dur = 1.minute
actor ! ScheduleStateClearing(dur)
there was one(mockScheduler).scheduleOnce(dur, actor, ClearState)(actor.underlyingActor.context.dispatcher)
}
}
"A ClearState message received by the actor" should{
"clear the interval 'state' List" in new testscope{
actor.underlyingActor.state = List(1,2,3)
actor ! ClearState
actor.underlyingActor.state mustEqual Nil
}
}
}
You can see that when I create the actor instance under test I override the method I created to get me the instance of the scheduler, allowing me to return a mock. This is not the only way to go about testing something like this, but it certainly can be one option for you to consider.
Make the scheduler take a time parameter. In your test use a shorter time than in your regular code.
Or... when testing you can mix in a special trait that modifies your class as needed (shortens the wait time.)
I have a singleton actor system in my application, and this works perfectly fine except that when the same application is loaded and unloaded inside the same JVM for testing, I have an error because I try, in my startup procedure, to recreate an actor which already exists.
As a result I get an akka.actor.InvalidActorNameException because the Actor name is not unique.
I am looking for a way to smoothly shutdown the actors depending on the actor systems without shutting down the actor system itself. Which is a reasonable strategy for that?
This is not exactly answer to your question - "... a way to smoothly shutdown the actors ...", but you mentioned that you are able to able to start two applicatons in same JVM.
Could you make your actor system to be singleton within application instance instead of singleton within whole JVM?
You would have two independent actor systems, you won't have name conflicts and won't have to start/stop specific actors.
I guess problems could be if some of actors are interacting with outside world, for example consuming some messages from JMS etc. Then it would not be obvious which actor system is processing them.
Do you want somethings like this ?
object AkkaTest extends App {
import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
val system = ActorSystem.create
val supervisor = system.actorOf(Props[MasterOfPuppets], name = "masterOfPuppets")
private object AllTerminated
private class MasterOfPuppets extends Actor {
var supervised = 0
var waiterForTerminated: Option[ActorRef] = None
def receive = {
case actor: ActorRef =>
context.watch(actor)
supervised += 1
case Terminated(dead) =>
supervised -= 1
if (supervised == 0) {
waiterForTerminated.map(_ ! AllTerminated)
waiterForTerminated = None
}
case AllTerminated =>
if (supervised == 0) {
sender ! AllTerminated
} else {
waiterForTerminated = Some(sender)
}
}
}
private class TestedActor extends Actor {
def receive = {
case a: Any => sender ! a
}
}
implicit val timeout = Timeout(5.seconds) // needed for `?` below
// Create first actor
val actor1 = system.actorOf(Props[TestedActor], name = "name1")
supervisor ! actor1
actor1 ! PoisonPill
val waitForIt = supervisor ? AllTerminated
Await.result(waitForIt, 5.seconds)
// Same name
val actor2 = system.actorOf(Props[TestedActor], name = "name1")
supervisor ! actor2
println("ok then")
}
Your problem is very simple : Akka and message are asynchronous. If you try to create an actor just after you kill him, the name is not available.
Try just a Thread.sleep before creating new actor and it will work.. :)
I am writing a program using Actors in scala in which an actor (Actor1) accepts two numbers as command line arguments and sends a message to another actor Actor2 (which calculates their sum). Actor2 sends the result to Actor1, who prints it on the screen.
class Actor1 extends Actor {
def main(args: Array[String]) {
val n= Integer.parseInt(args(0))
val k= Integer.parseInt(args(1))
val actor2 = new Actor2
actor2 ! (n, k)
}
def act()
{
react{
case num: Integer =>
println(num)
case _=>
println("Sum not received")
exit
}
}
}
class Actor2 extends Actor {
def act(){
loop
{
react
{
case(n:Int, k:Int) =>
val i = n + k
val actor1 = new Actor1
actor1 ! i}
}
}
}
Is it possible to define main() inside the class that extends Actor, and is there any other way to accept command line arguments by the Actor?
It shows the error: class Actor1 needs to be abstract, since method act in trait Reactor of type ()Unit is not defined.
First things first: You should consider using akka instead of the default Scala actors. It's just better.. in pretty much every aspect.
That aside, here are a few answers for your:
Your main method should be in a standalone object (not a companion object). So use something like this: object Main { def main(args:Array[String]) { ... } } and start your program via the Main object/class. (This is due to the definition inside the Actor1 class being non-static and the problem that if you define a companion object the .class filenames collide.)
In your code, something seems to have gone wrong with the brackets - or did you place Actor2 inside the Actor1 class on purpose? It's cleaner, if you just make three separate classes/objects: Actor1, Actor2, Main.
When you create Scala actors, you have to explicitly start them (not so with akka 2.x). So you miss your calls to actor1.start and such. Note that your program will then not terminate before your actors have terminated, so don't wonder if it doesn't stop anymore after you add that.
Finally, some minor hints:
You may want to consider using !? and send back your answer to the original caller, as this also allows you to have a proper termination condition.
Integer.parseInt("0") can be written more simply as "0".toInt