Scala Akka Actor - Dead Letters encountered - scala

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
}
}
}

Related

I want to send second message to Actor as new Message

I have two actors for example, sender:
class ActorSender(actroReciever: ActorRef) extends Actor{
implicit val timeout = Timeout(100, TimeUnit.SECONDS)
override def receive: Receive = {
case "RUN" => {
val resp = Await.result(actroReciever ? "Msg", 100.seconds)
println("receive response " + resp)
};
case str:String => println(str)
case _ => println("Error type msg")
}
}
reciever:
class ActroReciever extends Actor{
override def receive: Receive = {
case str:String => {
val snd = sender()
snd ! "MessageFirst"
snd ! "MessageSecond"
}
}
}
And class for starting:
object Tester extends App {
val system = ActorSystem("system")
val receiver = system.actorOf(Props[ActroReciever](new ActroReciever()), "receiver")
val sender = system.actorOf(Props[ActorSender](new ActorSender(receiver)), "sender")
sender ! "RUN"
}
I want to send two messages to sender(), first as reply for "ask", second msg as "new Message", which ActorSender execute as "matching", how I can do it? Thanks
First, you know you should not use Await, right?
Second, ask (?) is not meant to be used within actors. ask creates a temporary actor which can only receive a single message. It is not your ActorSender receiving the answer, but the temporary actor created by ask. That's why you have the feeling you can only send 1 answer.
You are doing this wrong, you should simply send your message using actroReciever ! "Msg". No need to change anything on your ActroReciever.

postRestart and preRestart methods are not getting invoke in akka actots

I am following this tutorial here is my code
case class ArtGroupDeleteFromES (uuidList:List[String])
class ArtGroupDeleteESActor extends Actor{
val log = LoggerFactory.getLogger(this.getClass)
override def preStart() {
log.debug("preStart Starting ArtGroupDeleteESActor instance hashcode # {}",
this.hashCode())
}
override def postStop() {
log.debug("postStop Stopping ArtGroupDeleteESActor instance hashcode # {}",
this.hashCode())
}
override def preRestart(reason: Throwable, message: Option[Any]) {
log.debug("I am restarting")
log.debug("ArtGroupDeleteESActor: preRestart")
log.debug(s" MESSAGE: ${message.getOrElse("")}")
log.debug(s" REASON: ${reason.getMessage}")
super.preRestart(reason, message)
}
override def postRestart(reason: Throwable) {
log.debug("restart completed!")
log.debug("ArtGroupDeleteESActor: postRestart")
log.debug(s" REASON: ${reason.getMessage}")
super.postRestart(reason)
}
def receive = {
case ArtGroupDeleteFromES(uuidList) =>
throw new Exception("Booom")
sender ! true
}
case message =>
log.warn("Received unknown message: {}", message)
unhandled(message)
}
}
and here is the how i am sending this actor a message
class ArtGroupDeletionActor extends Actor{
val log = LoggerFactory.getLogger(this.getClass)
override val supervisorStrategy = OneForOneStrategy(
maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case _:Exception => Restart
}
val artGroupDeleteESActor=context.actorOf(Props[ArtGroupDeleteESActor]
.withDispatcher("akka.actor.ArtGroupDeleteESActor-dispatcher")
,name = "ArtGroupDeleteESActor")
def receive = {
case DeleteArtGroup(uuidList) =>
val future1 = ask(artGroupDeleteESActor, ArtGroupDeleteFromES(uuidList)).mapTo[Boolean]
var isDeletedfromES = Await.result(future1, timeout.duration)
case message =>
log.warn("Unhandled message received : {}", message)
unhandled(message)
}
}
object test extends App{
val artGroupDeletionActor=system.actorOf(Props[ArtGroupDeletionActor]
.withDispatcher("akka.actor.ArtGroupDeletionActor-dispatcher")
,name = "ArtGroupDeletionActor")
artGroupDeletionActor ! DeleteArtGroup(List("123"))
}
the PostRestart() and preRestart() methods are not invoking,but preStart() and postStop() gets called, please guide me where i am doing wrong
(for simplicity I'll call your actors Parent and Child from now on)
What happens here is that when an exception occurs inside Child.receive, it doesn't send a response to Parent, instead, the actor system sends some control instruction for the supervision strategy. However, Parent is blocked on Await waiting for completion of future1, which only happens after the timeout exceeds, and then, in turn, a TimeoutException is thrown inside Parent.receive, killing (restarting) the Parent actor itself, and thus the supervising message of an exception in Child is then passed to deadLetters, never restarting the Child.
You should never, ever, ever block inside an actor, so this is incorrect:
val future1 = ask(artGroupDeleteESActor, ArtGroupDeleteFromES(uuidList)).mapTo[Boolean]
var isDeletedfromES = Await.result(future1, timeout.duration)
Instead, you have to either utilize some kind of message identification to distinguish one reply from another in concurrent environment, or add an onComplete to the Future and send a message to self in the closure (beware: no logic other than sending a message should be executed inside the closure to the Future!).
So, option A:
case class ArtGroupDeleteFromES(id: Long, uuidList: List[String])
case class ArtGroupDeleteFromESResult(id: Long, success: Boolean)
class Parent extends Actor {
override val supervisionStrategy = ...
var msgId = 0L
var pendingRequesters = Map.empty[Long, ActorRef]
val child = context.actorOf(Props[Child])
def nextId = {
msgId += 1
msgId
}
def receive = {
case DeleteArtGroup(uuidList) =>
val id = nextId
pendingRequesters += id -> sender() // store a reference to the sender so that you can send it a message when everything completes
child ! DeleteArtGroupFromES(nextId, uuidList)
case ArtGroupDeleteFromESResult(id, success) =>
// process result...
pendingRequesters(id) ! "done"
pendingRequesters -= id
}
}
And option B:
case class ArtGroupDeleteFromES(uuidList: List[String])
case class ArtGroupDeleteFromESResult(replyTo: ActorRef, success: Boolean)
class Parent extends Actor {
override val supervisionStrategy = ...
val child = context.actorOf(Props[Child])
def receive = {
case DeleteArtGroup(uuidList) =>
val requester = sender() // when the future completes, sender may have already changed, so you need to remember it
(child ? DeleteArtGroupFromES(uuidList)).onComplete {
case Success(success) => self ! ArtGroupDeleteFromESResult(requester, success)
case Failure(e) =>
log.warn("Could not delete...", e)
self ! ArtGroupDeleteFromESResult(requester, success = false)
}
}

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

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 context.parent unexpected value

The context.parent reference does not do it, for me. In a Play project, I launch a new actor to deal with each incoming request:
val myActor: ActorRef = system.actorOf(Props(classOf[MyActor])
val future: Future[String] = (myActor ? Hello)(5.seconds).mapTo[String]
future.map(result => Ok(result)).recover {
case ex: AskTimeoutException => Ok("timeout expired")
case _ => Ok("error")
}
This triggers more actor messaging in the receive method of myActor: when anotherActor responds to myActor, the latter sends a message AllGood to its parent.
class MyActor extends Actor {
// other stuff, among which setup of anotherActor
def receive: Actor.Receive = {
case Hallo => anotherActor ! Hello
case HelloBack => context.parent ! AllGood
}
}
class AnotherActor extends Actor {
def receive: Actor.Receive = {
case Hallo => sender ! HelloBack
}
}
Everything works fine until myActor tries to send a message to context.parent. I get a deadLetters message in the console.
from Actor[xyz] to Actor[akka://my-system/user] was not delivered. [1] dead letters encountered.
I can make it work if myActor keeps a reference to the original sender, and the code looks like this instead:
class MyActor extends Actor {
var myDad: Option[ActorRef] = None // <--- NEW REFERENCE
// other stuff, among which setup of anotherActor
def receive: Actor.Receive = {
case Hallo => {
myDad = Some(sender)
anotherActor ! Hello
}
case HelloBack => myDad ! AllGood <-- MYDAD INSTEAD OF CONTEXT.PARENT
}
}
class AnotherActor extends Actor {
def receive: Actor.Receive = {
case Hallo => sender ! HelloBack
}
}
The reference myDad is actually something like Actor[akka://my-system/temp/$a], while I would expect it to be the same as the context.parent which was Actor[akka://my-system/user]. Isn't it the same actor?
Can anybody explain this behaviour to me, and suggest a cleaner way to fix this? Thanks.
Looks like you mixed up the concepts of parent and sender.
context.parent [akka://my-system/user] is normal because the actor has been created as a child of the Akka system using system.actorOf(Props(classOf[MyActor]).
the sender method gives you back the actor who sent the message. The important thing here is; this is not the actor system who sent the message to your actor. When using the ask pattern Akka creates a temporary actor (in your case Actor[akka://my-system/temp/$a]) that will send the message and wait for the answer. When the response is received, the Future is completed.
If you want it is possible to forward the original sender so that your AnotherActor can reply directly HelloBack to the temporary actor created by the ask pattern.
To do so just change the way the message is passed to anotherActor.
def receive: Actor.Receive = {
case Hallo => anotherActor.tell(Hello, sender)
}