Akka: Future to Actor communication? - scala

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

Related

Scala Akka Actor - Dead Letters encountered

I am using Scala with Akka actors. I know that an actor has a mailbox. So any communication with the actor is serialized. I have an actor that does a certain job--say it downloads an image.
class DownloadImageActor(implicit val injector: Injector) extends Actor with Injectable {
val imageDownloadService = inject[ImageDownloadService]
implicit val ec = inject[ExecutionContext]
override def receive: Receive = {
case DownloadImage(jobId, imageUrl) =>
imageDownloadService.downloadImage(imageUrl).onComplete {
case Success(image) =>
sender() ! ImageDownloadSuccess(imageUrl, image, jobId)
case Failure(e) =>
sender() ! ImageDownloadFail(imageUrl, e, jobId)
}
}
}
As you can see, the actor downloads the image in an async fashion. imageDownloadService.downloadImage returns a Future on whose completion a message is sent to the sender. Now this is where I get the dead letters encountered message.
Where have I gone wrong?
EDIT #1
The parent actor which sends message to the download actor
class ParentActor(implicit val injector : Injector) extends Actor with Injectable {
val downloadImageActor = inject[ActorRef](identified by "ImageDownloadActor")
override def receive: Receive = {
case DownloadImages(urls, _id) => urls.foreach(url =>
downloadImageActor ! DownloadImage(id, imageUrl = url)
)
case ImageDownloadSuccess(image : Image) =>
}
}
Don't know if any other problem, but the method you use sender in Future is wrong, you need to assign it to a new variable, then combine the onComplete callback it forms a closure which will not be override by other actor handle.
In your code, need to add lineA, and replace lineB, lineC with lineD, lineE. Or you may want to have a look for pipeTo function of Future.
class DownloadImageActor(implicit val injector : Injector) extends Actor with Injectable{
val imageDownloadService = inject[ImageDownloadService]
implicit val ec = inject[ExecutionContext]
override def receive: Receive = {
case DownloadImage(jobId, imageUrl) =>
val client = sender // lineA
imageDownloadService.downloadImage(imageUrl).onComplete {
//case Success(image) => sender() ! ImageDownloadSuccess(imageUrl, image, jobId) // lineB
//case Failure(e) => sender() ! ImageDownloadFail(imageUrl,e, jobId) // lineC
case Success(image) => client ! ImageDownloadSuccess(imageUrl, image, jobId) // lineD
case Failure(e) => client ! ImageDownloadFail(imageUrl,e, jobId) // lineE
}
}
}

Resolving Akka futures from ask in the event of a failure

I am calling an Actor using the ask pattern within a Spray application, and returning the result as the HTTP response. I map failures from the actor to a custom error code.
val authActor = context.actorOf(Props[AuthenticationActor])
callService((authActor ? TokenAuthenticationRequest(token)).mapTo[LoggedInUser]) { user =>
complete(StatusCodes.OK, user)
}
def callService[T](f: => Future[T])(cb: T => RequestContext => Unit) = {
onComplete(f) {
case Success(value: T) => cb(value)
case Failure(ex: ServiceException) => complete(ex.statusCode, ex.errorMessage)
case e => complete(StatusCodes.InternalServerError, "Unable to complete the request. Please try again later.")
//In reality this returns a custom error object.
}
}
This works correctly when the authActor sends a failure, but if the authActor throws an exception, nothing happens until the ask timeout completes. For example:
override def receive: Receive = {
case _ => throw new ServiceException(ErrorCodes.AuthenticationFailed, "No valid session was found for that token")
}
I know that the Akka docs say that
To complete the future with an exception you need send a Failure message to the sender. This is not done automatically when an actor throws an exception while processing a message.
But given that I use asks for a lot of the interface between the Spray routing actors and the service actors, I would rather not wrap the receive part of every child actor with a try/catch. Is there a better way to achieve automatic handling of exceptions in child actors, and immediately resolve the future in the event of an exception?
Edit: this is my current solution. However, it's quite messy to do this for every child actor.
override def receive: Receive = {
case default =>
try {
default match {
case _ => throw new ServiceException("")//Actual code would go here
}
}
catch {
case se: ServiceException =>
logger.error("Service error raised:", se)
sender ! Failure(se)
case ex: Exception =>
sender ! Failure(ex)
throw ex
}
}
That way if it's an expected error (i.e. ServiceException), it's handled by creating a failure. If it's unexpected, it returns a failure immediately so the future is resolved, but then throws the exception so it can still be handled by the SupervisorStrategy.
If you want a way to provide automatic sending of a response back to the sender in case of an unexpected exception, then something like this could work for you:
trait FailurePropatingActor extends Actor{
override def preRestart(reason:Throwable, message:Option[Any]){
super.preRestart(reason, message)
sender() ! Status.Failure(reason)
}
}
We override preRestart and propagate the failure back to the sender as a Status.Failure which will cause an upstream Future to be failed. Also, it's important to call super.preRestart here as that's where child stopping happens. Using this in an actor looks something like this:
case class GetElement(list:List[Int], index:Int)
class MySimpleActor extends FailurePropatingActor {
def receive = {
case GetElement(list, i) =>
val result = list(i)
sender() ! result
}
}
If I was to call an instance of this actor like so:
import akka.pattern.ask
import concurrent.duration._
val system = ActorSystem("test")
import system.dispatcher
implicit val timeout = Timeout(2 seconds)
val ref = system.actorOf(Props[MySimpleActor])
val fut = ref ? GetElement(List(1,2,3), 6)
fut onComplete{
case util.Success(result) =>
println(s"success: $result")
case util.Failure(ex) =>
println(s"FAIL: ${ex.getMessage}")
ex.printStackTrace()
}
Then it would properly hit my Failure block. Now, the code in that base trait works well when Futures are not involved in the actor that is extending that trait, like the simple actor here. But if you use Futures then you need to be careful as exceptions that happen in the Future don't cause restarts in the actor and also, in preRestart, the call to sender() will not return the correct ref because the actor has already moved into the next message. An actor like this shows that issue:
class MyBadFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
def receive = {
case GetElement(list, i) =>
val orig = sender()
val fut = Future{
val result = list(i)
orig ! result
}
}
}
If we were to use this actor in the previous test code, we would always get a timeout in the failure situation. To mitigate that, you need to pipe the results of futures back to the sender like so:
class MyGoodFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
import akka.pattern.pipe
def receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut pipeTo sender()
}
}
In this particular case, the actor itself is not restarted because it did not encounter an uncaught exception. Now, if your actor needed to do some additional processing after the future, you can pipe back to self and explicitly fail when you get a Status.Failure:
class MyGoodFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
import akka.pattern.pipe
def receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut.to(self, sender())
case d:Double =>
sender() ! d * 2
case Status.Failure(ex) =>
throw ex
}
}
If that behavior becomes common, you can make it available to whatever actors need it like so:
trait StatusFailureHandling{ me:Actor =>
def failureHandling:Receive = {
case Status.Failure(ex) =>
throw ex
}
}
class MyGoodFutureUsingActor extends FailurePropatingActor with StatusFailureHandling{
import context.dispatcher
import akka.pattern.pipe
def receive = myReceive orElse failureHandling
def myReceive:Receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut.to(self, sender())
case d:Double =>
sender() ! d * 2
}
}

Akka, futures and critical sections

Let's say we have an Akka actor, which maintains an internal state in terms of a var.
class FooActor extends Actor {
private var state: Int = 0
def receive = { ... }
}
Let's say the reception handler invokes an operation that returns a future, we map it using the dispatcher as context executor and finally we set a onSuccess callback that alters the actor state.
import context.dispatcher
def receive = {
case "Hello" => requestSomething() // asume Future[String]
.map(_.size)
.onSuccess { case i => state = i }
}
Is it thread-safe to alter the state of the actor from the onSuccess callback, even using the actor dispatcher as execution context?
No it's not (akka 2.3.4 documentation).
What you have to do in this case is send a message to self to alter the state. If you need ordering you can use stash and become. Something like this
import akka.actor.{Stash,Actor}
import akka.pattern.pipe
case class StateUpdate(i:int)
class FooActor extends Actor with Stash{
private var state: Int = 0
def receive = ready
def ready = {
case "Hello" => requestSomething() // asume Future[String]
.map(StateUpdate(_.size)) pipeTo self
become(busy)
}
def busy {
case StateUpdate(i) =>
state=i
unstashAll()
become(ready)
case State.Failure(t:Throwable) => // the future failed
case evt =>
stash()
}
}
Of course this is a simplistic implementation you will probably want to handle timeout and stuff to avoid having your actor stuck.
if you don't need ordering guarantees on your state :
case class StateUpdate(i:int)
class FooActor extends Actor with Stash{
private var state: Int = 0
def receive = {
case "Hello" => requestSomething() // asume Future[String]
.map(StateUpdate(_.size)) pipeTo self
case StateUpdate(i) => state=i
}
but then the actor state may not be the length of the last string received
Just to support Jean's answer here's the example from the docs :
class MyActor extends Actor {
var state = ...
def receive = {
case _ =>
//Wrongs
// Very bad, shared mutable state,
// will break your application in weird ways
Future {state = NewState}
anotherActor ? message onSuccess {
r => state = r
}
// Very bad, "sender" changes for every message,
// shared mutable state bug
Future {expensiveCalculation(sender())}
//Rights
// Completely safe, "self" is OK to close over
// and it's an ActorRef, which is thread-safe
Future {expensiveCalculation()} onComplete {
f => self ! f.value.get
}
// Completely safe, we close over a fixed value
// and it's an ActorRef, which is thread-safe
val currentSender = sender()
Future {expensiveCalculation(currentSender)}
}
}

Scala Akka Play, Future doesn't return

I'm using Scala 2.10, Akka 2.1 and Play 2.1. When I send an http request to my backend, I ask one actor to compute something. The idea is to return the result of the calculation if it returns before a timeout, otherwise a different string. See code below.
val futureInt: Future[Int] = ask(testActor, Calculate(number.toInt)).mapTo[Int]
val timeoutFuture = play.api.libs.concurrent.Promise.timeout("Oops", 2.seconds)
Async {
Future.firstCompletedOf(Seq(futureInt, timeoutFuture)).map {
case i: Int => Ok("Got result " + i)
case t: String => Ok("timeout expired")
}
}
The actor is as follows:
class TestActor() extends Actor {
def receive = {
case Calculate(tonumber: Int) =>
for (a <- 1 to tonumber) {
val c: Double = scala.math.pow(a, 2)
println("a: " + a + ", c: " + c)
}
12345 // hardcoded value to return when the calculation finishes
case _ =>
println("bah")
}
}
My problem is that even if the actor finishes before the timeout, nothing is "returned" by the Future and so the timeout always expires. What am I doing wrong? Thanks a lot.
From http://doc.akka.io/docs/akka/snapshot/scala/actors.html
Using ask will send a message to the receiving Actor as with tell, and the receiving actor must reply with sender ! reply in order to complete the returned Future with a value.
and
Warning
To complete the future with an exception you need send a Failure message to the sender. This is not done automatically when an actor throws an exception while processing a message.
So instead of "returning" like you would in a usual scala function, do something along the lines of
def receive = {
case Calculate(tonumber: Int) =>
...
sender ! 12345
case _ =>
sender ! akka.actor.Status.Failure(new InvalidArgumentException)
}

How to send a delayed response inside Scala actor

Non-actor class sends a synchronous message to actor like this:
val response = WorkData !? "hello"
If i want to respond to this message right away, than i will do this:
receive {
case "hello" => reply("world")
}
But if i need to reply some time in the future, than
how do i store the caller reference, and send the reply after that?
Reference to the current caller is stored at sender. E.g., it's perfectly valid to replace
receive {
case "hello" => reply("world")
}
with
receive {
case "hello" => sender ! "world"
}
You can store this ref hereafter in the mutable variable, or pass recursively through the actor's loop.
I generally store the sender reference to use it later.
receive {
case "hello" =>
val otherParty = sender
// more receives, etc
// ...
otherParty ! "world"
}
How about just spawning an anonymous actor that processes the message and respond when it's ready? This way the receiver just acts as a dispatcher. This does not need a mutable variable to store anything since you are using a closure here.
import scala.actors.Actor
import scala.actors.Actor._
case class Message(msg: String)
class MyReceiver extends Actor {
def act() {
react {
case Message(msg) =>
actor {
sender ! process(msg)
}
}
}
def process(msg: String): String =
"Result: " + msg
}
object Main {
def main(args: Array[String]) {
val a = new MyReceiver
a.start()
val res = a !? Message("foo")
println(res)
}
}
Regards, raichoo