Akka avoiding wrapping future when responding to non-Actor code - scala

I'm making a small caching actor with Akka 2 and to make the actor not block I perform all calculations inside futures. However a problem is that this actor also need to interact with with code that is not itself in an actor, so that I need to use the "ask" pattern to get a value.
My question is, how do I avoid wrapping the Future of my calculation inside another Future when using the ask pattern?
For example
val f = myCache ? GetOrCalc("myKey", myCalculation) // this will be a Future[Future[...]] but I would like a Future[...]
// meanwhile, inside the actor
def receive = {
case GetOrCalc(key, calculation) =>
if (keyNotExists) sender ! Future { calculation() } // calculation() is long-running
else sender ! cacheMap(key)
}
Ideally I could use the Future.pipeTo function but I'm afraid this doesn't get counted as a "response" for non-actor code

This is the solution:
val f = myCache ? GetOrCalc("myKey", myCalculation)
def receive = {
case GetOrCalc(key, calculation) =>
if (keyNotExists) Future { calculation() } pipeTo sender
else sender ! cacheMap(key)
}
Send-And-Receive-Future">http://doc.akka.io/docs/akka/2.0.3/scala/actors.html#Ask_Send-And-Receive-Future

Add onComplete to the calculation future.
def receive = {
case GetOrCalc(key, calculation) =>
if (keyNotExists) // calculation() is long-running
Future { calculation() } onComplete {
case Right(result) => result match {
case Some(value) => sender ! value
case None => sender ! Status.Failure(new Exception("Cannot find the value"))
}
case Left(ex) =>
sender ! Status.Failure(ex)
}
else sender ! cacheMap(key)
}
And there is an article about using Akka to build a cache system. http://letitcrash.com/post/30509298968/case-study-an-auto-updating-cache-using-actors

Related

Ask pattern which doesn't wait after result

I have an akka actor which is doing some things sequentially, it can be summarized like that :
def receive = {
case Request(...) => {
val id = generatedId()
sender() ! id
doSomeOtherStuffs()
}
}
The actor is called using some ask pattern
val id = myActor ? Request(...)
The problem here is the code calling my actor is waiting for all of the doSomeOtherStuffs() thing to complete.
What is the correct way to allow an actor to reply and then have the calling code stop waiting for that actor ?
How about this? Decouple the actual execution of other stuff from answering the Request
def receive = {
case Request(...) => {
val id = generatedId()
sender() ! id
self ! DoSomethingElse(...)
}
case DoSomethingElse(...) =>
doSomethingElse()
}

Akka: Future to Actor communication?

I have a system that spawns a single actor who will spawn many futures. Some of these futures will run into scenarios that need to spawn more futures (but tell the actor about it). How do I send a message from a future to an actor on the completion of the future's operations?
I've looked at the pipeTo documentation but I am having trouble referencing the actors in my system in my future class.
Here is what my Future class looks like:
class crawler(string: String) {
val status: Future[Boolean] = Future[Boolean] {
//Do something with content
println("I am a future working on cert crawling. My cert contents are: " + cert.content)
true
}
status onComplete {
case Success(true) =>
for(chars <- string.toCharArray) {
//send actor a message for each character of the string.
}
case Failure(t) => println("An error has occured: " + t.getMessage)
}
}
Where the actor's receive method does the following:
def receive = {
case c:Char => if(!certCache.containsKey(c)){
println("actor >>>> Need to begin crawl on " + c + ".")
sender() ! new crawler("give sender the future")
case _ => println("That's not the right input!")
}
And, my Actor is spawned like:
object Main extends App {
val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[actorClass], name = "actor")
actor ! 'a'
}
Directly
You could dependency inject the ActorRef into your Future (not recommended, see Abstracted) :
import akka.actor.ActorRef
//dependency injection of the ActorRef with a default value of noSender
class crawler(string : String, actorRef : ActorRef = ActorRef.noSender) {
...
status OnComplete {
//send each Char in string to the actorRef
case Success(true) => string.foreach(actorRef ! _)
...
}
Then in your Actor you can use self to pass the ActorRef into the crawler:
def receive = {
case c : Char => if(!certCache.containsKey(c)) {
sender() ! new crawler("give sender the future", self)
}
}
Abstracted
Further, you could abstract away the use of ActorRef entirely so that crawler doesn't need to know the details of messaging passing. This is the more "functional" approach which has the benefit of being extendable if you ever switch to Futures or even akka.stream.scaladsl.Source for reactive streams (see example):
//no akka imports or dependencies
class crawler(string : String, sendChar : (Char) => Unit) {
...
case Success(true) => string foreach sendChar
}
And in your Actor you can pass an anonymous function to crawler which sends a Char to the Actor via self:
def receive = {
case c : Char => if(!certCache.containsKey(c)) {
sender ! new crawler("give sender the future", self ! _)
}
}
You can even get robust and provide default "do nothing" behavior for your sendChar function:
class crawler(string : String, sendChar : (Char) => Unit = {_=>}) {
...
}
val crawler = crawler("foo") //still get regular Future behavior for status

Ask an actor and let him respond when he reaches a particular state in Akka 2

I'm quite new to Akka so my question may seem simple:
I have an actor called workerA that uses FSM and can thus be either in those two states Finishedand Computing:
sealed trait State
case object Finished extends State
case object Computing extends State
sealed trait Data
case object Uninitialized extends Data
case class Todo(target: ActorRef, queue: immutable.Seq[Any]) extends Data
When workerA receives GetResponse it should answer if and if only it is in state Finished.
What is the proper way of doing this? I know we should avoid to be blocking in this paradigm but here it is only the top actor which is concerned.
Thanks
I'm not necessarily sure you even need FSM here. FSM is a really good tool for when you have many states and many possible (and possibly complicated) state transitions between those states. In your case, if I understand correctly, you basically have two states; gathering data and finished. It also seems that there is only a single state transition, going from gathering -> finished. If I have this all correct, then I'm going to suggest that you simply use become to solve your problem.
I have some code below to show a trivial example of what I'm describing. The basic idea is that the main actor farms some work off to some workers and then waits for the results. If anyone asks for the results while the work is being done, the actor stashes that request until the work is done. When done, the actor will reply back to anyone that has asked for the results. The code is as follows:
case object GetResults
case class Results(ints:List[Int])
case object DoWork
class MainActor extends Actor with Stash{
import context._
override def preStart = {
val a = actorOf(Props[WorkerA], "worker-a")
val b = actorOf(Props[WorkerB], "worker-b")
a ! DoWork
b ! DoWork
}
def receive = gathering(Nil, 2)
def gathering(ints:List[Int], count:Int):Receive = {
case GetResults => stash()
case Results(i) =>
val results = i ::: ints
val newCount = count - 1
if (newCount == 0){
unstashAll()
become(finished(results))
child("worker-a") foreach (stop(_))
child("worker-b") foreach (stop(_))
}
else
become(gathering(results, newCount))
}
def finished(results:List[Int]):Receive = {
case GetResults => sender ! results
}
}
class WorkerA extends Actor{
def receive = {
case DoWork =>
//Only sleeping to simulate work. Not a good idea in real code
Thread sleep 3000
val ints = for(i <- 2 until 100 by 2) yield i
sender ! Results(ints.toList)
}
}
class WorkerB extends Actor{
def receive = {
case DoWork =>
//Only sleeping to simulate work. Not a good idea in real code
Thread sleep 2000
val ints = for(i <- 1 until 100 by 2) yield i
sender ! Results(ints.toList)
}
}
Then you could test it as follows:
val mainActor = system.actorOf(Props[MainActor])
val fut = mainActor ? GetResults
fut onComplete (println(_))
You can pattern match on FSM states:
// insert pattern matching stuff instead of ...
class MyActor extends Actor with FSM[State, Message] {
startWith(Finished, WaitMessage(null))
when(Finished) {
case Event(Todo(... =>
// work
goto(Computing) using Todo(...)
case Event(GetResponse(... =>
// reply: sender ! msg // or similar
}
/* the rest is optional. You can use onTransition below to send yourself a message to report status of the job: */
when(Busy) {
case Event(Finished(... =>
// reply to someone: sender ! msg // or similar
goto(Finished)
}
onTransition {
case Finished -> Computing =>
// I prefer to run stuff here in a future, and then send a message to myself to signal the end of the job:
self ! Finished(data)
}
An Edit to more specifically address the question:
class MyActor extends Actor with FSM[State, Message] {
startWith(Finished, WaitMessage(null))
when(Finished) {
case Event(Todo(... =>
// work
goto(Computing) using Todo(...)
case Event(GetResponse(... =>
// reply: sender ! msg // or similar
stay
}
initialize()
}

Akka: Send a future message to an Actor

I have the following code inside an Actor
def receive = {
case All() => {
val collection: BSONCollection = db("ping")
val future:Future[List[Ping]] = collection.find(BSONDocument()).cursor[Ping].toList()
val zender = sender
future onComplete {
case Success(list) => zender ! list
case Failure(throwable) => zender ! List()
}
}
}
I don't like how I have to use the onComplete function to send the result back to the sender actor. I'd like to know if it is possible to convert it into something like this:
def receive = {
case All() => {
val collection: BSONCollection = db("ping")
val future:Future[List[Ping]] = collection.find(BSONDocument()).cursor[Ping].toList()
"sender ! future" // one option
"future.map( list => sender ! list)" //Another option. I know it's not map, but maybe another function
}
}
I feel that this flows better with future chaining.
You can use the pipe pattern for that. Just import akka.pattern.pipe and then you'll be able to pipe messages from futures to actors with future pipeTo actor.
If you want to have an empty list when failure happens, you probably want to have chained calls of "recover" and "pipeTo".

How to handle multiple Promises in an (akka) Actor?

I have an Akka actor responsible of handling http calls. I use scala dispatch to send multiple HTTP requests over an API:
urls.foreach { u
val service = url(u)
val promise = Http(service OK as.String).either
for(p <- promise)
{
p match
{
case Left(error) =>
faultHandler(error)
case Right(result) =>
resultHandler(result)
}
}
In the resultHandlerfunction, I increment an instance variable nbOfResults and compare to the number of calls I have done.
def resultHandler(result:String)
{
this.nbOfResults++
...
if(nbOfResults == nbOfCalls)
// Do something
}
Is it safe ? May the nbOfResultsvaraible be accessed at the same time if two calls return their results simultaneously ?
For now, I believed that the actor is more or less equivalent to a thread and therefore the callback functions are not executed concurrently. Is it correct ?
Here is a variant of Alexey Romanov response using only dispatch :
//Promises will be of type Array[Promise[Either[Throwable, String]]]
val promises = urls.map { u =>
val service = url(u)
Http(service OK as.String).either
}
//Http.promise.all transform an Iterable[Promise[A]] into Promise[Iterable[A]]
//So listPromise is now of type Promise[Array[Either[Throwable, String]]]
val listPromise = Http.promise.all(promises)
for (results <- listPromise) {
//Here results is of type Array[Either[Throwable, String]]
results foreach { result =>
result match {
Left(error) => //Handle error
Right(response) => //Handle response
}
}
}
There is a far better way:
val promises = urls.map {u =>
val service = url(u)
val promise = Http(service OK as.String).either
}
val listPromise = Future.sequence(promises)
listPromise.onComplete { whatever }
I agree with Alexey Romanov on his answer. Whatever way you choose to synchronize your http requests beware of the way your are processing the promises completion. Your intuition is correct in that concurrent access may appear on the state of the actor. The better way to handle this would be to do something like this:
def resultHandler(result: String) {
//on completion we are sending the result to the actor who triggered the call
//as a message
self ! HttpComplete(result)
}
and in the actor's receive function:
def receive = {
//PROCESS OTHER MESSAGES HERE
case HttpComplete(result) => //do something with the result
}
This way, you make sure that processing the http results won't violate the actor's state from the exterior, but from the actor's receive loop which is the proper way to do it
val nbOfResults = new java.util.concurrent.atomic.AtomicInteger(nbOfCalls)
// After particular call was ended
if (nbOfResults.decrementAndGet <= 0) {
// Do something
}
[EDIT] Removed old answer with AtomicReference CAS - while(true), compareAndSet, etc