Akka : the proper use of `ask` pattern? - scala

I'm trying to grok Futures and ask pattern in akka.
So, I make two actors, and one asking another to send him back a message. Well, according to akka's Futures documentation, actor should ask(?) for message and it shall give him a Future instanse. Then actor should block (using Await) to get Future results.
Well, I never get my future done. Why is that?
Code is:
package head_thrash
import akka.actor._
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration._
object Main extends App {
val system = ActorSystem("actors")
val actor1 = system.actorOf(Props[MyActor], "node_1")
val actor2 = system.actorOf(Props[MyActor], "node_2")
actor2 ! "ping_other"
system.awaitTermination()
Console.println("Bye!")
}
class MyActor extends Actor with ActorLogging {
import akka.pattern.ask
implicit val timeout = Timeout(100.days)
def receive = {
case "ping_other" => {
val selection = context.actorSelection("../node_1")
log.info("Sending ping to node_1")
val result = Await.result(selection ? "ping", Duration.Inf) // <-- Blocks here forever!
log.info("Got result " + result)
}
case "ping" => {
log.info("Sending back pong!")
sender ! "pong"
}
}
}
If I change Duration.Inf to 5.seconds, then actor waits 5 seconds, tells that my future is Timeouted (by throwing TimeoutException), and then other actor finally replies with needed message. So, no async happens. Why? :-(
How should I properly implement that pattern? Thanks.

The official Akka documentation says that Await.result will cause the current thread to block and wait for the Actor to 'complete' the Future with it's reply.
It is strange that your code blocks there forever, do you have only one thread for all your application?
Anyway I guess a more "idiomatic" way to code it would be to use a callback on the future success.
def receive = {
case "ping_other" => {
val selection = context.actorSelection("../node_1")
log.info("Sending ping to node_1")
val future: Future[String] = ask(selection, "ping").mapTo[String]
future.onSuccess {
case result : String ⇒ log.info("Got result " + result)
}
}
...

Two reasons why that doesn't work.
First, "node_1" asks itself and the "ping" will not be processed because it is blocking in waiting for the ask.
Also, there is a shortcoming of actorSelection for relative paths ("../node_1"). It is processed with message passing, and since your actor is blocking it cannot process any other message. This has been improved in upcoming 2.3 version of Akka, but you should avoid blocking anyway.

Related

How to continually call a REST service using non blocking code with Akka

I'm accessing data from a REST endpoint :
"https://api-public.sandbox.pro.coinbase.com/products/BTC-EUR/ticker"
To access the data once per second I use an infinite loop while(true) { to invoke a message send to the actor once per second which begins the process of invoking the REST request:
The actor to access the data is:
object ProductTickerRestActor {
case class StringData(data: String)
}
class ProductTickerRestActor extends Actor {
override def receive: PartialFunction[Any, Unit] = {
case ProductTickerRestActor.StringData(data) =>
try {
println("in ProductTickerRestActor")
val rData = scala.io.Source.fromURL("https://api-public.sandbox.pro.coinbase.com/products/BTC-EUR/ticker").mkString
println("rData : "+rData)
}
catch {
case e: Exception =>
println("Exception thrown in ProductTickerRestActor: " + e.getMessage)
}
case msg => println(s"I cannot understand ${msg.toString}")
}
}
I start the application using:
object ExchangeModelDataApplication {
def main(args: Array[String]): Unit = {
val actorSystem = ActorSystemConfig.getActorSystem
val priceDataActor = actorSystem.actorOf(Props[ProductTickerRestActor], "ProductTickerRestActor")
val throttler = Throttlers.getThrottler(priceDataActor)
while(true) {
throttler ! ProductTickerRestActor.StringData("test")
Thread.sleep(1000)
}
}
Throttler:
object Throttlers {
implicit val materializer = ActorMaterializer.create(ActorSystemConfig.getActorSystem)
def getThrottler(priceDataActor: ActorRef) = Source.actorRef(bufferSize = 1000, OverflowStrategy.dropNew)
.throttle(1, 1.second)
.to(Sink.actorRef(priceDataActor, NotUsed))
.run()
}
How to run the following code asynchronously instead of blocking using an infinite loop? :
throttler ! ProductTickerRestActor.StringData("test")
Thread.sleep(1000)
Also, the throttler, in this case, maybe redundant as I'm throttling requests within the loop regardless.
I would just use Akka Streams for this along with Akka HTTP. Using Akka 2.6.x, something along these lines would be sufficient for 1 request/second
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.scaladsl._
import scala.concurrent.duration._
object HTTPRepeatedly {
implicit val system = ActorSystem()
import system.dispatcher
val sourceFromHttp: Source[String, NotUsed] =
Source.repeated("test") // Not sure what "test" is actually used for here...
.throttle(1, 1.second)
.map { str =>
HttpRequest(uri = "https://api-public.sandbox.pro.coinbase.com/products/BTC-EUR/ticker")
}.mapAsync(1) { req =>
Http().singleRequest(req)
}.mapAsync(1)(_.entity.toStrict(1.minute))
.map(_.data.decodeString(java.nio.charset.StandardCharsets.UTF_8))
}
Then you could, for instance (for simplicity, put this in a main within HTTPRepeatedly so the implicits are in scope etc.)
val done: Future[Done] =
sourceFromHttp
.take(10) // stop after 10 requests
.runWith(Sink.foreach { rData => println(s"rData: $rData") })
scala.concurrent.Await.result(done, 11.minute)
system.terminate()
Sending a request every second is not a good idea. If, for some reason, the request is delayed, you are going to get a lot of requests piled up. Instead, send the next request one second after the previous requests completes.
Because this code uses a synchronous GET request, you can just send the next request one second after mkString returns.
But using synchronous requests is not a good way to consume a RESTful API in Akka. It blocks the actor receive method until the request is complete, which can eventually block the whole ActorSystem.
Instead, use Akka Http and singleRequest to perform an asynchronous request.
Http().singleRequest(HttpRequest(uri = "https://api-public.sandbox.pro.coinbase.com/products/BTC-EUR/ticker"))
This returns a Future. Make the new request one second after the request completes (e.g. using onComplete on the Future).
Not only is this safer and more asynchronous, it also provides much more control over the REST API call than fromUrl

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

Scala and Akka: Background job

I'm working currently on a Play application with a background job which should send mails periodically for which I want to use Akka. I have to add that I'm really new to Scala/Play/Akka.
Currently I have the following setup:
// JobModule.scala
bind(classOf[MailJobScheduler]).asEagerSingleton()
This should start up the following piece of code which does work every second
// MailJobScheduler.scala
val mailActor = actorSystem.actorOf(MailActor.props, "mail-actor")
actorSystem.scheduler.schedule(0 seconds, 1 seconds) {
// check how many mails have to be sent and sent messages to the mailActor
}
It might be that each second multiple new mails should be send. I am wondering: in case I send every second 10 messages to the mailActor will it be really only one actor having to do all the work or will there be multiple actors doing the work concurrently?
If it is one actor how can I have multiple actors for which I can assign the work and how many can/should I have?
How about using Akka streams instead?
import akka.Done
import akka.stream.{KillSwitch, KillSwitches, OverflowStrategy}
import akka.stream.scaladsl.{Keep, Sink, Source}
import scala.concurrent.duration._
import scala.concurrent.Future
object BatchEmailSender {
sealed trait Msg
case object Tick extends Msg
case class Email(toAddress: String, body: String) extends Msg
def apply(sendEmail: Email => Future[Done], sendInterval: FiniteDuration = 10.seconds)(implicit mat: ActorMaterializer)
: (Email => Unit, KillSwitch) = {
val emailQueue = scala.collection.mutable.Queue[Email]()
val (emailCmdQueue, killSwitch) = Source.queue[Msg](0, OverflowStrategy.backpressure)
.merge(Source.tick(0.seconds, sendInterval, Tick))
.viaMat(KillSwitches.single)(Keep.both)
.toMat(Sink.foreach {
case newEmail: Email =>
emailQueue.enqueue(newEmail)
case Tick =>
emailQueue.dequeueAll(_ => true).foreach { email =>
sendEmail(email).onFailure { case e =>
println(s"Error sending email to ${email.toAddress}: $e")
}
}
})(Keep.left)
.run()
(emailCmdQueue.offer(_), killSwitch)
}
}
You need a sendEmail function, and then it would work like this:
import scala.concurrent.ExecutionContext.Implicits.global // TODO: remove me
object TestApp extends App {
import BatchEmailSender._
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
def sendEmail(email: Email): Future[Done] ={
println(s"Sending email $email") // TODO: insert real email sender code here
Future.successful(Done)
}
val (sendEmailEvery10s, killSwitch) = BatchEmailSender(sendEmail)
sendEmailEvery10s(Email("foo#bar.com", "Email will arrive in 10s"))
sendEmailEvery10s(Email("foo#bar.com", "Email will arrive in same batch"))
Thread.sleep(11000)
sendEmailEvery10s(Email("foo#bar.com", "Email will arrive after another 10s"))
Thread.sleep(11000)
killSwitch.shutdown()
}
I may have just complicated your life, but Akka streams lets you do these things without worrying about which actor does what, has back-pressure and typically is much more robust code.
I would have used 1 actor if Akka streams did not exist. Accumulate all messages in the actor and then send a tick to itself periodically.
Use the scheduler as you are doing in your example, but I don't see how the mailActor helps you here.
actorSystem.scheduler.schedule(0 seconds, 1 seconds) {
// just call the code the the checks for email
}
Don't assume that there will be one thread. i.e. be extra careful to not close over unstable references

Akka Actor - wait for some time to expect a message, otherwise send a message out

Is it possible to make an Actor wait for X amount of seconds to receive any message, and if a message is received, process it as usual, otherwise send a message to some other Actor (pre-determined in the constructor)?
It's possible, have a look at Akka Actor "ask" and "Await" with TimeoutException. But keep in mind that blocking inside an actor is a very bad idea since during that time actor can't handle any other messages. Moreover it blocks one Akka processing thread.
A better approach is to send a message (fire and forget) and schedule some timeout event using Akka scheduler. When the response arrives, cancel that event or set some flag so that it won't trigger if the reply actually came on time.
Yes, if you want to wait for any message, you simply set a receiveTimeout: http://doc.akka.io/docs/akka/current/scala/actors.html#receive-timeout
(The docs is slightly misleading here, you can set the receiveTimeout after every message also)
Might be an overkill, but you might check out the Finite State Machine (FSM) trait.
import akka._
import actor._
import util._
import duration._
import Impatient._
object Impatient {
sealed trait State
case object WaitingForMessage extends State
case object MessageReceived extends State
case object TimeoutExpired extends State
sealed trait Data
case object Unitialized extends Data
// In
case object Message
}
class Impatient(receiver: ActorRef) extends Actor with FSM[State, Data] {
startWith(WaitingForMessage, Unitialized)
when(WaitingForMessage, stateTimeout = 3 seconds) {
case Event(StateTimeout, data) => goto(TimeoutExpired) using data // data is usually modified here
case Event(Message, data) => goto(MessageReceived) using data // data is usually modified here
}
onTransition {
case WaitingForMessage -> MessageReceived => stateData match {
case data => log.info("Received message: " + data)
}
case WaitingForMessage -> TimeoutExpired => receiver ! TimeoutExpired
}
when(MessageReceived) {
case _ => stay
}
when(TimeoutExpired) {
case _ => stay
}
initialize
}
Here it is in action:
object Main extends App {
import akka._
import actor._
import Impatient._
val system = ActorSystem("System")
val receiver = system.actorOf(Props(new Actor with ActorLogging {
def receive = {
case TimeoutExpired => log.warning("Timeout expired")
}
}))
val impatient = system.actorOf(Props(new Impatient(receiver)), name = "Impatient")
impatient ! Message
val impatient2 = system.actorOf(Props(new Impatient(receiver)), name = "Impatient2")
Thread.sleep(4000)
impatient2 ! Message
system.shutdown()
}

program hangs when using multiple futures with multiple remote actors

I start two remote actors on one host which just echo whatever is sent to them. I then create another actor which sends some number of messages (using !! ) to both actors and keep a List of Future objects holding the replies from these actors. Then I loop over this List fetching the result of each Future. The problem is that most of the time some futures never return, even thought the actor claims it has sent the reply. The problem happens randomly, sometimes it will get through the whole list, but most of the time it gets stuck at some point and hangs indefinitely.
Here is some code which produces the problem on my machine:
Sink.scala:
import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.Exit
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
object Sink {
def main(args: Array[String]): Unit = {
new RemoteSink("node03-0",43001).start()
new RemoteSink("node03-1",43001).start()
}
}
class RemoteSink(name: String, port: Int) extends Actor
{
def act() {
println(name+" starts")
trapExit=true
alive(port)
register(Symbol(name),self)
loop {
react {
case Exit(from,reason) =>{
exit()
}
case msg => reply{
println(name+" sending reply to: "+msg)
msg+" back at you from "+name
}
}
}
}
}
Source.scala:
import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.remote.Node;
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
object Source {
def main(args: Array[String]):Unit = {
val peer = Node("127.0.0.1", 43001)
val source = new RemoteSource(peer)
source.start()
}
}
class RemoteSource(peer: Node) extends Actor
{
def act() {
trapExit=true
alive(43001)
register(Symbol("source"),self)
val sinks = List(select(peer,Symbol("node03-0"))
,select(peer,Symbol("node03-1"))
)
sinks.foreach(link)
val futures = for(sink <- sinks; i <- 0 to 20) yield sink !! "hello "+i
futures.foreach( f => println(f()))
exit()
}
}
What am I doing wrong?
I'm guessing your problem is due to this line:
futures.foreach( f => println(f()))
in which you loop through all your futures and block on each in turn, waiting for its result. Blocking on futures is generally a bad idea and should be avoided. What you want to do instead is specify an action to carry out when the future's result is available. Try this:
futures.foreach(f => f.foreach(r => println(r)))
Here's an alternate way to say that with a for comprehension:
for (future <- futures; result <- future) { println(result) }
This blog entry is an excellent primer on the problem of blocking on futures and how monadic futures overcome it.
I have seen a similar case as well. When the code inside the thread throws certain types of exception and exits, the corresponding future.get never returns. One can try with raising an exception of java.lang.Error vs java.lang.NoSuchMethodError. The latter's corresponding future would never return.