Scala and Akka: Background job - scala

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

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.

switch actor behavior with akka and scala

What is the correct way to switch activity between actors.
for example
actorA - send 100 messages to the actorB.
ActorB will print it into console. After 100 messages actorB will send 100 messages to the actorA and actorA will print it. Switch actor behaviour each 100 msg.
Thansk
Here's how I would do it (this is a very quick solution, probably not the most elegant one, suggestions for improvement are welcome). The main part is the following actor which can either send or receive messages. It changes its behaviour after sending (respectively receiving) more than numberOfMessages messages.
import akka.actor._
import scala.concurrent.duration._
object SenderReceiver {
case class StartSending(other: ActorRef) // see explanation below
case object TheMessage // dummy placeholder for actual message
case object SendMessage // a reminder for the actor itself to send a message
def props(numberOfMessages: Int): Props = Props(new SenderReceiver(numberOfMessages))
}
class SenderReceiver(numberOfMessages: Int) extends Actor with ActorLogging {
import context._
import SenderReceiver._
// initial receive in order to determine the actor's initial role
def receive = {
case StartSending(other) =>
log.info("I'm sending first, yay!")
sendNext(0, other)
case TheMessage =>
log.info("It seems, I'm receiving messages first.")
become(receiveMessages(1))
}
// receive function for when actor is a receiver of messages
def receiveMessages(messagesReceived: Int) : Receive = {
case TheMessage =>
log.info("Message received")
val messagesReceivedNew = messagesReceived + 1
if (messagesReceivedNew < numberOfMessages - 1)
become(receiveMessages(messagesReceivedNew))
else
sendNext(0, sender)
}
// receive function for when actor is a sender of messages
def sendMessages(messagesSent: Int, other: ActorRef) : Receive = {
case SendMessage =>
other ! TheMessage
log.info("Message sent")
val messagesSentNew = messagesSent + 1
if (messagesSentNew < numberOfMessages - 1)
sendNext(messagesSentNew, other)
else
become(receiveMessages(0))
}
def sendNext(messagesSent: Int, other: ActorRef) {
system.scheduler.scheduleOnce(500 milliseconds, self, SendMessage)
become(sendMessages(messagesSent, other))
}
}
Initially, the actor is in a state where it does not know yet whether it is a sender or a receiver. In this case, two things may happen:
Either the actor receives a message, in this case, it knows it is a receiver, and therefore becomes a receiver.
In the other case, the actor needs to be explicitely told that it is a sender (in particular, it needs to know where to send to!), before it can become a sender.
Once the actor knows what its role is, it does exactly what it is supposed to do. It sends (or receives) a certain number of messages, and afterwards switches to the other behavior.
In order to run this code, here are some more snippets you might need. First, here's some simple auxiliary actor that sets up the whole system and stops it after a while (it gets a bit boring after ten seconds or so...)
object Terminator {
case object StopThem
}
class Terminator extends Actor with ActorLogging {
import Terminator._
import SenderReceiver.StartSending
import context._
val actorA = system.actorOf(SenderReceiver.props(3), "actorA")
val actorB = system.actorOf(SenderReceiver.props(3), "actorB")
actorB ! StartSending(actorA)
system.scheduler.scheduleOnce(10 seconds, self, StopThem)
def receive = {
case StopThem =>
log.info("Stopping actors now")
system.shutdown
}
}
And, for the sake of completeness, a simple App to start everything
object SenderReceiverAkka extends App {
val system = ActorSystem("test")
val terminator = system.actorOf(Props[Terminator])
}

Akka : the proper use of `ask` pattern?

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.

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