Alejandro Alcalde
Alejandro Alcalde

Reputation: 6220

Get a message out of an Akka Actor

I've built an Akka actor that queries an API at regular intervals, like this:

  val cancellable =
    system.scheduler.schedule(0 milliseconds,
      5 seconds,
      actor,
      QueryController(1))

The Actor, in essence is:

object UpdateStatistics {
  /**
   * Query the controller for the given switch Id
   *
   * @param dpId Switch's Id
   */
  case class QueryController(dpId: Int)
  case object Stop

  def props: Props = Props[UpdateStatistics]
}

class UpdateStatistics extends Actor with akka.actor.ActorLogging {
  import UpdateStatistics._

  def receive = {

    case QueryController(id) =>
      import context.dispatcher
      log.info(s"Receiving request to query controller")
      Future { FlowCollector.getSwitchFlows(1) } onComplete {
        f => self ! f.get
      }
    case Stop =>
      log.info(s"Shuting down")
      context stop self
    case json: JValue =>
      log.info("Getting json response, computing features...")
      val features = FeatureExtractor.getFeatures(json)
      log.debug(s"Features: $features")
      sender ! features
    case x =>
      log.warning("Received unknown message: {}", x)
  }
}

What I am trying to do is get the json:Jvalue message out of UpdateStatistics actor. Reading the Akka docs I thought this may be useful:

  implicit val i = inbox()
  i.select() {
     case x => println(s"Valor Devuelto $x")
  }
  println(i receive(2.second))

But I do not know how to modify UpdateStatistics actor in order to send the result to the inbox above.

Another option I've read in the docs are event streams.

But I do not think this is the correct way.

Is there a way of achieving what I want to do? Or do I need to use a second Actor to which I send the JSON response?

Upvotes: 2

Views: 1312

Answers (1)

Jon Anderson
Jon Anderson

Reputation: 696

You probably are looking for the ask pattern in AKKA. This will allow you to return a value to the sender.

import akka.pattern.ask
import akka.util.duration._

implicit val timeout = Timeout(5 seconds)

val future = actor ? QueryController(1)    
val result = Await.result(future, timeout.duration).asInstanceOf[JValue]

println(result)

To make this work, you need to send the response to the original sender, rather than self. Also, you should beware the dangers of closing over sender in a future when handling messages.

Upvotes: 5

Related Questions