Akka actor get remaining message list - scala

I have an actor computing something intensive, and only the last result ideally should count.
I would like that if it receive multiple messages of the same type A(data), only the last one is handled and the previous ones are discarded.
How can I achieve that?

Custom mailbox
You can try implement some custom mailbox, containing 0 or 1 message:
import akka.actor.{ActorRef, ActorSystem}
import akka.dispatch._
import com.typesafe.config.Config
class SingleMessageQueue extends MessageQueue {
var message = Option.empty[Envelope]
def enqueue(receiver: ActorRef, handle: Envelope) = message = Some(handle)
def dequeue() = {
val handle = message.orNull
message = None
handle
}
def numberOfMessages = message.size
def hasMessages = message.nonEmpty
def cleanUp(owner: ActorRef, deadLetters: MessageQueue) = message.foreach(deadLetters.enqueue(owner, _))
}
final case class SingleMessageMailbox() extends MailboxType with ProducesMessageQueue[SingleMessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue = new SingleMessageQueue
}
and next enable it for your actor as descrived in the mailbox section of the docs
Split actors
You can introduce pair of actors.
Manager, receiving a job, resending it to Worker whenever it's not working right now
Worker doing actual work and notifing it's manager when it's done
example:
import akka.actor.{Actor, ActorRef, Props}
object Worker {
case class Job()
case object JobDone
}
import Worker.{Job, JobDone}
class Worker extends Actor {
override def receive = {
case Job() ⇒
// your long job
context.parent ! JobDone
}
}
class Manager extends Actor {
var nextJob = Option.empty[(Job, ActorRef)]
val worker = context.actorOf(Props[Worker])
def working: Receive = {
case job: Job ⇒ nextJob = Some((job, sender))
case JobDone ⇒
nextJob match {
case Some((job, snd)) ⇒ worker.tell(job, snd)
case None ⇒ context.become(free)
}
}
def free: Receive = {
case job: Job ⇒
worker.tell(job, sender)
context.become(working)
}
override def receive = free
}

Related

In Akka, how do I manage blocking method calls, like reading from StdIn?

I'm beginning to using Scala and the AKKA pattern, and i have wrote this code, but it doesn't work and i don't know why...
I have created a little project that read user input from the console.
when this user have wrote a 'keyword', the keyWord Actor (Child) will interpret it and will communicate with the console Actor (Grand parent).
the action Actor will be use to broadcast and do some more stuff.
When i enter the command 'rename' in the console Actor, i enter into the action Actor and after that in the keyWord Actor and enter in the Rename Method, but after that nothing, i didn't enter into the rename method on the console Actor.
Can you help me ?
If you saw any wrong pratice, please don't hesite to tell me how to resolve that :).
Thank you !
Main
import ConsoleActor._
import akka.actor.ActorSystem
object Main extends App {
val system = ActorSystem("My-Little-IRC")
val consoleActor = system.actorOf(ConsoleActor.props, "consoleActor")
consoleActor ! ReadConsoleInput
system.terminate()
}
consoleActor
import ActionActor.TreatInputUser
import akka.actor.{Actor, Props}
import scala.io.StdIn
object ConsoleActor {
case class ReadConsoleInput()
case class StopLoop()
case class Rename()
case class WhoIAm()
def props = Props[ConsoleActor]
}
class ConsoleActor() extends Actor {
val keyWordActor = context.actorOf(KeyWordActor.props(this.self), "keyWordActor")
val actionActor = context.actorOf(ActionActor.props(keyWordActor), "actionActor")
var currentUser: String = ""
var loop: Boolean = true;
import ConsoleActor._
def isValidString( str: String ): Boolean = {
var isValid: Boolean = false
if (str != null && !str.trim().isEmpty)
isValid = true
isValid
}
def initiatePresentation( ) = {
println("Hi ! Who are you ?")
currentUser = StdIn.readLine()
println(s"Nice to meet you ${currentUser}, I'm your console app !")
}
def receive = {
case ReadConsoleInput => {
initiatePresentation
var value = ""
while (loop) {
println("Yes ?")
value = StdIn.readLine()
if (isValidString(value)) {
actionActor ! TreatInputUser(value)
}
}
}
case StopLoop => {
println("stop Loooop !")
loop = false
}
case Rename => {
println(s"${currentUser} was a good name ! Which is your new name ?")
currentUser = StdIn.readLine()
println(s"Nice to meet you -again- ${currentUser}")
}
case WhoIAm =>{
println(s"I'm ${currentUser}")
}
}
}
actionActor
import ActionActor.TreatInputUser
import akka.actor.{Actor, ActorRef, Props}
import akka.util.Timeout
import scala.concurrent.duration._
import akka.pattern.ask
import scala.concurrent.Await
object ActionActor {
case class TreatInputUser(string: String)
def props(keyWordActor: ActorRef) = Props(new ActionActor(keyWordActor))
}
class ActionActor(keyWordActor: ActorRef) extends Actor {
import KeyWordActor._
def receive = {
case TreatInputUser(string) => {
implicit val timeout = Timeout(5 seconds)
var isKeyWord = keyWordActor ? IsKeyWord(string)
val isKeyWordResult = Await.result(isKeyWord, timeout.duration).asInstanceOf[ Boolean ]
println(isKeyWordResult)
if (isKeyWordResult) {
keyWordActor ! HandleKeyWord(string)
}
else {
println("bla bla bla")
}
}
}
}
keyWord actor
import ConsoleActor.{Rename, StopLoop, WhoIAm}
import akka.actor.{Actor, ActorRef, Props}
object KeyWordActor {
case class IsKeyWord(key : String)
case class HandleKeyWord(key : String)
def props(consoleActor: ActorRef) = Props(new KeyWordActor(consoleActor))
}
class KeyWordActor(consoleActor: ActorRef) extends Actor {
import KeyWordActor._
val KeysWord : Map[ String, ()=> Any] = Map("rename" -> renameFunction, "stop" -> stopFunction, "42" -> uselessfunction, "john doe ?" -> AmIJohnDoe)
def renameFunction() = {
println("here")
consoleActor ! Rename
}
def stopFunction() = {
consoleActor ! StopLoop
}
def uselessfunction() = {
println("useless")
}
def AmIJohnDoe() ={
consoleActor ! WhoIAm
}
def receive = {
case IsKeyWord(key) => {
sender ! KeysWord.contains(key.toLowerCase)
}
case HandleKeyWord(key) => {
if (KeysWord.contains(key.toLowerCase)) {
KeysWord(key.toLowerCase)()
}
}
}
}
You must not block in the receive method. The way you wrote it (with a while loop), the initial ReadConsoleInput message never finishes processing, and any subsequent messages (like StopLoop) will sit untouched in the Actor mailbox forever.
If you must selectively read from StdIn (as opposed to just continuously reading in e.g. your Main class) then one approach could be to change your ConsoleActor so that when it receives a ReadConsoleInput message, it should just try to do StdIn.readLine once, and forward the result to the ActionActor. Since the StdIn.readLine call itself is also blocking, you should do it asynchronously. The "pipe" pattern comes in handy here:
import akka.pattern.pipe
import scala.concurrent.Future
//...
def receive = {
case ReadConsoleInput =>
import context.dispatcher //provide a thread pool to do async work
Future(StdIn.readLine()) //read a line of input asynchronously
.filter(isValidString) //only continue if line is valid
.map(TreatInputUser) //wrap the (valid) String in a message
.pipeTo(actionActor) //forward it
case Rename => ...
}
This way, the ConsoleActor immediately becomes available again to process new messages, while your ActionActor will receive a TreatInputUser message whenever the user finishes typing a line in the console.
You can apply the same pattern inside your ActionActor, instead of relying on Await.
If you want to close the loop so you can continue sending messages, I'd use behaviour to ensure that two StdIn.readLine calls are not interfering.

I can't get a child actor to receive messages

I'm new to akka and I'm wondering how to get a child actor to receive messages.
I have one parent actor which prints out that it received a message and then sends a message to its child which then prints out that it received a message.
When I run the program, only the parent actor prints its message. Is there
something I'm missing?
The parent actor
class TestDirector(name: String) extends Actor {
import TestDirector._
implicit val timeout = Timeout(5.seconds)
private var child: ActorRef = _
override def preStart(): Unit = {
println(name + " pre-start")
child = context.actorOf(props("test-file"), name = "child-actor")
}
override def receive: Receive = {
case TestDirectory(dir) =>
println("Test Director")
child ! TestWorker.TestFile
}
}
object TestDirector {
case class TestDirectory(dirName: String)
case class TestResponse(message: String)
def props(dirName: String) = Props(classOf[TestDirector], dirName)
}
The child actor
class TestWorker(fileName: String) extends Actor {
import TestWorker._
override def receive: Receive = {
case TestFile => println("Hello world")
}
}
object TestWorker {
case object TestFile
def props(fileName: String) = Props(classOf[TestWorker], fileName)
}
In TestDirector.preStart, you say
child = context.actorOf(props("test-file"), name = "child-actor")
Those "props" are TestDirector.props, which you imported a few lines above, so you're endlessly creating new TestDirectors. I think what you want instead is TestWorker.props:
child = context.actorOf(TestWorker.props("test-file"), name = "child-actor")

Data push using akka scheduler

I am looking for some example on akka scheduler usage. I have one actor (lets call it - dataProducer) implementation for retrieving data from some database. I would like to write one scheduler actor which will pole the dataProducer actor in 5 seconds interval. Also how to handle the case if data retrieval takes more time than scheduler interval. Will scheduleOnce method in Scheduler actor handle this?
Here is my scheduler actor
import java.util.concurrent.{Executors, TimeUnit}
import akka.actor.{Actor, Cancellable, Props}
import scala.concurrent.ExecutionContext
class SchedulerActor(interval: Long) extends Actor with LogF{
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(100))
private var scheduler: Cancellable = _
override def preStart(): Unit = {
import scala.concurrent.duration._
scheduler = context.system.scheduler.schedule(
initialDelay = 0 seconds,
interval = FiniteDuration(interval, TimeUnit.SECONDS),
receiver = self,
message = FetchData
)
}
override def postStop(): Unit = {
scheduler.cancel()
}
def receive = {
case FetchData =>
logger.debug( "Fetch Data" )
sender() ! "Data Fetched!!!" //here I'll call dataProducer API
true
case unknown =>
throw new RuntimeException( "ERROR: Received unknown message [" + unknown + "], can't handle it" )
}
}
object SchedulerActor {
def props(interval: Long): Props = Props(new SchedulerActor(interval))
}
sealed trait FetchDataMessage
case object FetchData extends FetchDataMessage
Scheduler's scheduleOnce helps to execute a piece of after some delay.
Have different states and switch between states to accept different kind of messages and act accordingly. But when timeout happens scheduleOnce will take you to timeoutState.
ScheduleOnce will help the actor know that timeout has happened.
how to handle the case if data retrieval takes more time than scheduler interval ?
If data fetch takes more than specified time actor state changes timeoutState and in the timeout state say what should be done to the actor. Either you can retry or try different source.
I would like to write one scheduler actor which will pole the dataProducer actor in 5 seconds interval
In the result state wait for scheduleOnce with 5 seconds delay to request the dataProducer and whole thing repeats again.
Check this code to understand how it can be done.
import akka.actor.{Actor, Cancellable}
import stackoverflow.DBUtils.Entity
import scala.concurrent.Future
import scala.concurrent.duration._
import akka.pattern.pipe
object DBPollActor {
case class Result(results: List[Entity])
case object Schedule
case object Timeup
case object FetchData
}
object DBUtils {
case class Entity(name: String)
def doDBOperation: Future[List[Entity]] = {
Future.successful(List(Entity(name = "foo")))
}
}
class DBPollActor(timeout: Int) extends Actor {
import DBPollActor._
implicit val ex = context.system.dispatcher
var schedulerOpt: Option[Cancellable] = None
#scala.throws[Exception](classOf[Exception])
override def preStart(): Unit = {
super.preStart()
self ! FetchData
schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
context become timeoutState
self ! Timeup
})
}
override def receive: Receive = {
case msg#FetchData =>
context become startState
self forward msg
}
def startState: Receive = {
case FetchData =>
schedulerOpt.map(_.cancel())
context become resultState
DBUtils.doDBOperation.map(Result) pipeTo self
schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
context become timeoutState
self ! Timeup
})
}
def timeoutState: Receive = {
case Timeup =>
schedulerOpt.map(_.cancel())
//Timeout happened do something or repeat
}
def resultState: Receive = {
case result#Result(list) =>
schedulerOpt.map(_.cancel())
//Result available consume the result and repeat or doSomething different
context become resultState
DBUtils.doDBOperation.map(Result) pipeTo self
schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
context become timeoutState
self ! Timeup
})
case ex: Exception =>
schedulerOpt.map(_.cancel())
//future failed exit or retry
}
}

Testing Akka Typed behavior

How would I test that a given behavior sends the messages I expect?
Say, three messages of some type, one after the other...
With regular actors (untyped) there was the TestProbe from regular Akka with methods like expectedMsg:
http://doc.akka.io/api/akka/current/index.html#akka.testkit.TestProbe
With akka-typed I'm scratching my head still. There is something called EffectfulActorContext, but I've no idea how to use that.
Example
Say I am writing a simple PingPong service, that given a number n replies with Pong(n) n-times. So:
-> Ping(2)
Pong(2)
Pong(2)
-> Ping(0)
# nothing
-> Ping(1)
Pong(1)
Here is how this behavior might look:
case class Ping(i: Int, replyTo: ActorRef[Pong])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => (0 until i.max(0)).map(_=> replyTo ! Pong(i))
}
}
My Hack
Now since I can't figure out how to make this work, the "hack" that I am doing right now is making the actor always reply with a list of responses. So the behavior is:
case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => replyTo ! (0 until i.max(0)).map(_=>Pong(i)).toList
}
}
Given this hacky change, the tester is easy to write:
package com.test
import akka.typed.AskPattern._
import akka.typed.ScalaDSL._
import akka.typed.{ActorRef, ActorSystem, Behavior, Props}
import akka.util.Timeout
import com.test.PingPong.{Ping, Pong}
import org.scalatest.{FlatSpec, Matchers}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
object PingPongTester {
/* Expect that the given messages arrived in order */
def expectMsgs(i: Int, msgs: List[Pong]) = {
implicit val timeout: Timeout = 5 seconds
val pingPongBe: ActorSystem[Ping] = ActorSystem("pingPongTester", Props(PingPong.pingPong))
val futures: Future[List[Pong]] = pingPongBe ? (Ping(i, _))
for {
pongs <- futures
done <- {
for ((actual, expected) <- pongs.zip(msgs)) {
assert(actual == expected, s"Expected $expected, but received $actual")
}
assert(pongs.size == msgs.size, s"Expected ${msgs.size} messages, but received ${pongs.size}")
pingPongBe.terminate
}
} Await.ready(pingPongBe.whenTerminated, 5 seconds)
}
}
object PingPong {
case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => replyTo ! (0 until i.max(0)).map(_=>Pong(i)).toList
}
}
}
class MainSpec extends FlatSpec with Matchers {
"PingPong" should "reply with empty when Pinged with zero" in {
PingPongTester.expectMsgs(0, List.empty)
}
it should "reply once when Pinged with one" in {
PingPongTester.expectMsgs(1, List(Pong(1)))
}
it should "reply with empty when Pinged with negative" in {
PingPongTester.expectMsgs(-1, List.empty)
}
it should "reply with as many pongs as Ping requested" in {
PingPongTester.expectMsgs(5, List(Pong(5), Pong(5), Pong(5), Pong(5), Pong(5)))
}
}
I'm using EffectfulActorContext for testing my Akka typed actors and here is an untested example based on your question.
Note: I'm also using the guardianactor provided in the Akka-typed test cases.
class Test extends TypedSpec{
val system = ActorSystem("actor-system", Props(guardian()))
val ctx: EffectfulActorContext[Ping] = new EffectfulActorContext[Ping]("ping", Ping.props(), system)
//This will send the command to Ping Actor
ctx.run(Ping)
//This should get you the inbox of the Pong created inside the Ping actor.
val pongInbox = ctx.getInbox("pong")
assert(pongInbox.hasMessages)
val pongMessages = pongInbox.receiveAll()
pongMessages.size should be(1) //1 or whatever number of messages you expect
}
Edit (Some more info): Cases where I need to add a replyTo ActorRef in my messages I do the following:
case class Pong(replyTo: ActorRef[Response])
val responseInbox: SyncInbox[Response] = Inbox.sync[Response]("responseInbox")
Pong(responseInbox.ref)
My initial approach to testing was to extend Behavior class
class TestQueueBehavior[Protocol] extends Behavior[Protocol] {
val messages: BlockingQueue[Protocol] = new LinkedBlockingQueue[Protocol]()
val behavior: Protocol => Unit = {
(p: Protocol) => messages.put(p)
}
def pollMessage(timeout: FiniteDuration = 3.seconds): Protocol = {
messages.poll(timeout.toMillis, TimeUnit.MILLISECONDS)
}
override def management(ctx: ActorContext[Protocol], msg: Signal): Behavior[Protocol] = msg match {
case _ ⇒ ScalaDSL.Unhandled
}
override def message(ctx: ActorContext[Protocol], msg: Protocol): Behavior[Protocol] = msg match {
case p =>
behavior(p)
Same
}
}
then I could call behavior.pollMessage(2.seconds) shouldBe somethingToCompareTo which was very similar to using TestProbe.
Although I think EffectfulActorContext is the right way to go, unfortunately couldn't figure out how to properly use it.

Ways for heartbeat message

I am trying to set a heartbeat over a network, i.e. having an actor send a message to the network on a fixed period of time. I would like to know if you have any better solution than the one I used below as I feel is pretty ugly, considering synchronisation contraints.
import akka.actor._
import akka.actor.Actor
import akka.actor.Props
import akka.actor.ScalaActorRef
import akka.pattern.gracefulStop
import akka.util._
import java.util.Calendar
import java.util.concurrent._
import java.text.SimpleDateFormat
import scala.Array._
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
sealed trait Message
case class Information() extends Message//does really need to be here?
case class StartMessage() extends Message
case class HeartbeatMessage() extends Message
case class StopMessage() extends Message
case class FrequencyChangeMessage(
f: Int
) extends Message
class Gps extends Actor {
override def preStart() {
val child = context.actorOf(Props(new Cadencer(500)), name = "cadencer")
}
def receive = {
case "beat" =>
//TODO
case _ =>
println("gps: wut?")
}
}
class Cadencer(p3riod: Int) extends Actor {
var period: Int = _
var stop: Boolean = _
override def preStart() {
period = p3riod
stop = false
context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
}
def receive = {
case StartMessage =>
stop = false
context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
case HeartbeatMessage =>
if (false == stop) {
context.system.scheduler.scheduleOnce(0 milliseconds, context.parent, "beat")
context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
}
case StopMessage =>
stop = true
case FrequencyChangeMessage(f) =>
period = f
case _ =>
println("wut?\n")
//throw exception
}
}
object main extends App {
val system = akka.actor.ActorSystem("mySystem")
val gps = system.actorOf(Props[Gps], name = "gps")
}
What I called cadencer here sends to a target actor and to itself an HeartbeatMessage ; to itself to transmit the order to resend one after a given amount of time, and thus going on with the process till a StopMessage (flipping the stop to true). Good?
Is even having a separated actor efficient rather than having it within a greater one?
Try this. It does not need a separate cadencer class.
class Gps extends Actor
{
var ticker : Cancellable = _
override def preStart()
{
println ("Gps prestart")
// val child = context.actorOf(Props(new Cadencer(500)), name = "cadencer")
ticker = context.system.scheduler.schedule (
500 milliseconds,
500 milliseconds,
context.self,
"beat")
}
def receive: PartialFunction[Any, Unit] =
{
case "beat" =>
println ("got a beat")
case "stop" =>
ticker.cancel()
case _ =>
println("gps: wut?")
}
}
object main extends App
{
val system = akka.actor.ActorSystem("mySystem")
val gps = system.actorOf(Props[Gps], name = "gps")
Thread.sleep (5000)
gps ! "stop"
println ("stop")
}
Actors are pretty lightweight, so it is no problem to have one actor for sending heartbeat messages (and it's preferable if you think of the Single Responsibility Principle).
Further remarks:
If you want to get rid of the period var, you can do the following (it's called hotswapping):
override def preStart() {
// ...
context.become(receive(p3riod))
}
def receive(period: Int) = {
// ...
case FrequencyChangeMessage(f) =>
context.become(receive(f))
// ...
}
Instead of using the stop var, you can stop the actor after getting the StopMessage.
If you need a heartbeat actor again, just start a new one.
Instead of scheduling with 0 milliseconds, you can send the message directly to the parent.