I've found in Akka docs:
When using future callbacks, such as onComplete, onSuccess, and onFailure, inside actors you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback.
So does it mean that i should always use future pipeTo self and then call some functions? Or i can still use callbacks with method, then how should i avoid concurrency bugs?
It means this:
class NotThreadSafeActor extends Actor {
import context.dispatcher
var counter = 0
def receive = {
case any =>
counter = counter + 1
Future {
// do something else on a future
Thread.sleep(2000)
}.onComplete {
_ => counter = counter + 1
}
}
}
In this example, both the actor's receive method, and the Future's onComplete change the mutable variable counter. In this toy example its easier to see, but the Future call might be nested methods that equally capture a mutable variable.
The issue is that the onComplete call might execute on a different thread to the actor itself, so its perfectly possible to have one thread executing receive and another executing onComplete thus giving you a race condition. Which negates the point of an actor in the first place.
Yes, you should send a message to the enclosing actor if the callback mutates internal state of the actor. This is the easiest (and preferred) way to avoid races.
I think I would be remiss if I did not mention here that I've made a small utility for circumventing this limitation. In other words, my answer to your question is No, you shouldn't use such an inconvenient workaround, you should use https://github.com/makoConstruct/RequestResponseActor
how does it work?
Basically, behind the futures and the promises, it transmits every query in a Request(id:Int, content:Any), and when it receives Response(id, result) it completes the future that corresponds to id with the value of result. It's also capable of transmitting failures, and as far as I can tell, akka can only register query timeouts. The RequestResponseActor supplies a special implicit execution context to apply to callbacks attached to the futures waiting for a Response message. This blunt execution context ensures they're executed while the Response message is being processed, thus ensuring the Actor has exclusive access to its state when the future's callbacks fire.
Maybe this can help. It is an experiment I did and the test is quite conclusive... however, it is still an experiment, so do not take that as an expertise.
https://github.com/Adeynack/ScalaLearning/tree/master/ActorThreadingTest/src/main/scala/david/ActorThreadingTest
Open to comments or suggestions, of course.
Futures with actors is a subject I am very interested in.
Related
I'm working on implementing a small language to send tasks to execution and control execution flow. After the sending a task to my system, the user gets a future (on which it can call a blocking get() or flatMap() ). My question is: is it OK to send futures in Akka messages?
Example: actor A sends a message Response to actor B and Response contains a future among its fields. Then at some point A will fulfill the promise from which the future was created. After receiving the Response, B can call flatMap() or get() at any time.
I'm asking because Akka messages should be immutable and work even if actors are on different JVMs. I don't see how my example above can work if actors A and B are on different JVMs. Also, are there any problems with my example even if actors are on same JVM?
Something similar is done in the accepted answer in this stackoverflow question. Will this work if actors are on different JVMs?
Without remoting it's possible, but still not advisable. With remoting in play it won't work at all.
If your goal is to have an API that returns Futures, but uses actors as the plumbing underneath, one approach could be that the API creates its own actor internally that it asks, and then returns the future from that ask to the caller. The actor spawned by the API call is guaranteed to be local to the API instance and can communicate with the rest of the actor system via the regular tell/receive mechanism, so that there are no Futures sent as messages.
class MyTaskAPI(actorFactory: ActorRefFactory) {
def doSomething(...): Future[SomethingResult] = {
val taskActor = actorFactory.actorOf(Props[MyTaskActor])
taskActor ? DoSomething(...).mapTo[SomethingResult]
}
}
where MyTaskActor receives the DoSomething, captures the sender, sends out the request for task processince and likely becomes a receiving state for SomethingResult which finally responds to the captured sender and stops itself. This approach creates two actors per request, one explicitly, the MyTaskActor and one implicitly, the handler of the ask, but keeps all state inside of actors.
Alternately, you could use the ActorDSL to create just one actor inline of doSomething and use a captured Promise for completion instead of using ask:
class MyTaskAPI(system: System) {
def doSomething(...): Future[SomethingResult] = {
val p = Promise[SomethingResult]()
val tmpActor = actor(new Act {
become {
case msg:SomethingResult =>
p.success(msg)
self.stop()
}
}
system.actorSelection("user/TaskHandler").tell(DoSomething(...), tmpActor)
p.future
}
}
This approach is a bit off the top of my head and it does use a shared value between the API and the temp actor, which some might consider a smell, but should give an idea how to implement your workflow.
If you're asking if it's possible, then yes, it's possible. Remote actors are basically interprocess communication. If you set everything up on both machines to a state where both can properly handle the future, then it should be good. You don't give any working example so I can't really delve deeper into it.
I am currently evaluating javascript scripts using Rhino in a restful service. I wish for there to be an evaluation time out.
I have created a mock example actor (using scala 2.10 akka actors).
case class Evaluate(expression: String)
class RhinoActor extends Actor {
override def preStart() = { println("Start context'"); super.preStart()}
def receive = {
case Evaluate(expression) ⇒ {
Thread.sleep(100)
sender ! "complete"
}
}
override def postStop() = { println("Stop context'"); super.postStop()}
}
Now I run use this actor as follows:
def run {
val t = System.currentTimeMillis()
val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[RhinoActor])
implicit val timeout = Timeout(50 milliseconds)
val future = (actor ? Evaluate("10 + 50")).mapTo[String]
val result = Try(Await.result(future, Duration.Inf))
println(System.currentTimeMillis() - t)
println(result)
actor ! PoisonPill
system.shutdown()
}
Is it wise to use the ActorSystem in a closure like this which may have simultaneous requests on it?
Should I make the ActorSystem global, and will that be ok in this context?
Is there a more appropriate alternative approach?
EDIT: I think I need to use futures directly, but I will need the preStart and postStop. Currently investigating.
EDIT: Seems you don't get those hooks with futures.
I'll try and answer some of your questions for you.
First, an ActorSystem is a very heavy weight construct. You should not create one per request that needs an actor. You should create one globally and then use that single instance to spawn your actors (and you won't need system.shutdown() anymore in run). I believe this covers your first two questions.
Your approach of using an actor to execute javascript here seems sound to me. But instead of spinning up an actor per request, you might want to pool a bunch of the RhinoActors behind a Router, with each instance having it's own rhino engine that will be setup during preStart. Doing this will eliminate per request rhino initialization costs, speeding up your js evaluations. Just make sure you size your pool appropriately. Also, you won't need to be sending PoisonPill messages per request if you adopt this approach.
You also might want to look into the non-blocking callbacks onComplete, onSuccess and onFailure as opposed to using the blocking Await. These callbacks also respect timeouts and are preferable to blocking for higher throughput. As long as whatever is way way upstream waiting for this response can handle the asynchronicity (i.e. an async capable web request), then I suggest going this route.
The last thing to keep in mind is that even though code will return to the caller after the timeout if the actor has yet to respond, the actor still goes on processing that message (performing the evaluation). It does not stop and move onto the next message just because a caller timed out. Just wanted to make that clear in case it wasn't.
EDIT
In response to your comment about stopping a long execution there are some things related to Akka to consider first. You can call stop the actor, send a Kill or a PosionPill, but none of these will stop if from processing the message that it's currently processing. They just prevent it from receiving new messages. In your case, with Rhino, if infinite script execution is a possibility, then I suggest handling this within Rhino itself. I would dig into the answers on this post (Stopping the Rhino Engine in middle of execution) and setup your Rhino engine in the actor in such a way that it will stop itself if it has been executing for too long. That failure will kick out to the supervisor (if pooled) and cause that pooled instance to be restarted which will init a new Rhino in preStart. This might be the best approach for dealing with the possibility of long running scripts.
When process a message, is it possible to send out an message to another actor and wait for that actor to reply, and consume the replied message and then continue, like the following, is it doable?
val lineMap=HashMap[String,Int]()
receive {
case bigTaskMap=>
for (line <-readSomeFile){
if(lineMap.get(line)==None){
anotherActor!line // that actor will reply a hashmap which contain the key for line
receive {
case x:HashMap => lineMap=x
}
}
lineMap.get(line) // use that value to do further work
}
}
This answer is for Akka (old Scala actors are deprecated in Scala 2.10).
Yes. You can use ask to get a future (rather than creating a fully-fledged actor yourself) and then call onComplete on the Future returned to set an action which will be executed when the Future's value (or an error) becomes available. Don't worry about how quickly the Future might yield a value - it doesn't matter, because the onComplete action will be executed even if the Future is already available when onComplete is called!
However, be very careful: you should not directly access any of the state (i.e. the variables) in the containing actor in your action(s), because the onComplete action(s) will not run in the same execution context as the actor (i.e. they could be running at the same time as the original actor is processing a message). Instead, send further messages back to the original actor, or forward them on.
In fact, in some cases you may find the simplest thing to do is simply to send a message, and let the original actor handle the reply. become and unbecome may help here. However, again, be careful if using become, that in the actor's new behaviour, it doesn't drop "ordinary" messages that should be handled in the ordinary way.
Just getting started on Scala Actors. The Scala website says:
Thread-blocking operations can be avoided by using react to wait for
new messages (the event-based pendant of receive). However, there is a
(usually small) price to pay: react never returns.
...
Note that using react inside a while loop does not work! However,
since loops are common there is special library support for it in form
of a loop function. It can be used like this:
loop {
react {
case A => ...
case B => ...
}
}
I'm now confused - there seems to be a contradiction:
a) If react never returns, then what's the point of putting it in a loop?
b) Since loop repeatedly executes a block, how is it any different to while(true) - why doesn't while work, and in what way does it "not work"?
Both functions, loop and react are not pure. loop takes a call by name parameter and react a PartialFunction, both set variables on the raw actor. This is because an actor does not have a thread attached all the time. It will become active only when there is a message in it's messagebox. This is why a while(true) will lead to 100% cpu usage and the actor not responding.
I found an explanation that answers part a) of my question, in one of Haller and Odersky's papers on Actors (my emphasis below):
The central idea is as follows: An actor that waits in a receive
statement is not represented by a blocked thread but by a closure that
captures the rest of the actor's computation. The closure is executed
once a message is sent to the actor that matches one of the message
patterns specied in the receive. The execution of the closure is
\piggy-backed" on the thread of the sender.
If the receiving closure
terminates, control is returned to the sender as if a procedure
returns. If the receiving closure blocks in a second receive, control
is returned to the sender by throwing a special exception that unwinds
the receiver's call stack.
A necessary condition for the scheme to
work is that receivers never return normally to their enclosing actor.
In other words, no code in an actor can depend on the termination or
the result of a receive block...
What is a good way of creating non-blocking methods in Scala? One way I can think of is to create a thread/actor and the method just send a message to the thread and returns. Is there a better way of creating a non-blocking method?
Use scala.actors.Future:
import actors._
def asyncify[A, B](f: A => B): A => Future[B] = (a => Futures.future(f(a)))
// normally blocks when called
def sleepFor(seconds: Int) = {
Thread.sleep(seconds * 1000)
seconds
}
val asyncSleepFor = asyncify(sleepFor)
val future = asyncSleepFor(5) // now it does NOT block
println("waiting...") // prints "waiting..." rightaway
println("future returns %d".format(future())) // prints "future returns 5" after 5 seconds
Overloaded "asyncify" that takes a function with more than one parameter is left as an exercise.
One caveat, however, is exception handling. The function that is being "asyncified" has to handle all exceptions itself by catching them. Behavior for exceptions thrown out of the function is undefined.
Learn about actors.
It depends on your definition of "blocking." Strictly speaking, anything that requires acquisition of a lock is blocking. All operations that are dependent on an actor's internal state acquire a lock on the actor. This includes message sends. If lots of threads try to send a message to an actor all-at-once they have to get in line.
So if you really need non-blocking, there are various options in java.util.concurrent.
That being said, from a practical perspective actors give you something that close enough to non-blocking because none of the synchronized operations do a significant amount of work, so chances are actors meet your need.