Search code examples
scalaakkaactorfuture

Execution context for futures in Actors


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?


Solution

  • 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.