7
votes

I have a Actor, and on some message I'm running some method which returns Future.

 def receive: Receive = {

    case SimpleMessge() =>
        val futData:Future[Int] = ...
        futData.map { data =>
           ... 
        }
}

Is it possible to pass actual context to wait for this data? Or Await is the best I can do if I need this data in SimpleMessage?

1
What exactly are you looking to do with the data that comes from the Future?cmbaxter
This are data from my db (mongo), and I want to filter them and only some part of them save to another collection. But basically this are db data, I cannot run this in background, and I have to wait to finish this action before next SimpleMessage.Michał Jurczuk
Is it sending a message back to the sender or no?Michael Zajac
No, without waiting for responseMichał Jurczuk

1 Answers

10
votes

If you really need to wait for the future to complete before processing the next message, you can try something like this:

object SimpleMessageHandler{
  case class SimpleMessage()
  case class FinishSimpleMessage(i:Int)
}

class SimpleMessageHandler extends Actor with Stash{
  import SimpleMessageHandler._
  import context._
  import akka.pattern.pipe

  def receive = waitingForMessage
  def waitingForMessage: Receive = {

    case SimpleMessage() =>
      val futData:Future[Int] = ...
      futData.map(FinishSimpleMessage(_)) pipeTo self
      context.become(waitingToFinish(sender))
  }

  def waitingToFinish(originalSender:ActorRef):Receive = {
    case SimpleMessage() => stash()

    case FinishSimpleMessage(i) =>
      //Do whatever you need to do to finish here
      ...
      unstashAll()
      context.become(waitingForMessage)

    case Status.Failure(ex) =>
      //log error here
      unstashAll()
      context.become(waitingForMessage)      
  }
}

In this approach, we process a SimpleMessage and then switch handling logic to stash all subsequent SimpleMessages received until we get a result from the future. When we get a result, failure or not, we unstash all of the other SimpleMessages we have received while waiting for the future and go on our merry way.

This actor just toggles back and forth between two states and that allows you to only fully process one SimpleMessage at a time without needing to block on the Future.