Data push using akka scheduler - scala

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

Related

Akka actor get remaining message list

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
}

Akka ask returns nothing when tell is used in future

The following code uses 2 asks and initially seems like it supposed to print "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing".
However there seems to be a race condition between the 'receive' method finishing and the future finishing and thus nothing is printed.
Is this the intended behavior by akka? is this a bug?
I am trying to avoid using 'ask' as much as possible and using 'tell' instead, but sometimes it's a must.
import akka.actor._
import akka.routing.SmallestMailboxPool
import akka.util.Timeout
import akka.pattern.ask
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
object ActorsAskingStuff extends App {
val system = ActorSystem("abc-system")
val actor1 = system.actorOf(Props[Actor1].withRouter(SmallestMailboxPool(1)), "actor1")
actor1 ! 5
}
class Actor1 extends Actor {
implicit val timeout = Timeout(60 seconds)
val actor2: ActorRef = context.actorOf(Props[Actor2].withRouter(SmallestMailboxPool(1)), "actor2")
override def receive: Receive = {
case _ =>
println("actor1 was called")
actor2 ? "hello" onComplete {
case Success(a) => println(a)
case Failure(b) => println("FAILURE")
}
}
}
class Actor2 extends Actor {
implicit val timeout = Timeout(6 seconds)
val actor3: ActorRef = context.actorOf(Props[Actor3].withRouter(SmallestMailboxPool(1)), "actor3")
override def receive: Actor.Receive = {
case _ =>
println("actor2 was called")
actor3 ? "hello" map {
_ =>
println("Actor2 completed the future")
sender ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
}
// uncomment this to make it work
//Thread.sleep(100)
}
}
class Actor3 extends Actor {
override def receive: Actor.Receive = {
case _ =>
println("actor3 was called")
sender ! "I'm actor3"
}
}
You are closing over the sender when you do this:
actor3 ? "hello" map {
_ =>
println("Actor2 completed the future")
sender ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
}
At that point the sender could have changed. In order to avoid closing over the sender you can rewrite like this:
val originator = sender()
actor3 ? "hello" map {
_ =>
println("Actor2 completed the future")
originator ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
}
Once you go into a Future based callback (like onComplete or map for example) at that point, the actor thinks it's done precessing the current message and moves onto the next message in the mailbox (if there is one). When this happens, the sender() which is just a def that returns the value of a var that is subject to change will return either a new ActorRef (more messages) or nothing (deadletter) if no messages.
You can checkout this post for more info:
sender inside a future

How to wait actors stop in scala

class A extends Actor{
def act = {
//do something
}
}
val a = new A
a.join // How Can I implement it
I have read How can I join started Actor?
however I still don't know how to write the code.
The standard way to achieve this would be to use the Ask Pattern
It goes something like this:
class MyActor extends Actor {
def receive = {
case "Ping" => sender ! "Pong"
}
}
val future = actor ? "Ping"
val result = Await.result(future, 10 seconds) //blocks until the response has been received, or the timeout reached
This is assuming that you want to block on a message from the actor. If you want to tell when an actor has died, you need to use DeathWatch like this:
case object TellMeWhenActorDies
case object ActorDied
class Watcher extends Actor {
val child = context.actorOf(Props[Watched], "watched")
context.watch(child)
override def receive: Receive = {
case TellMeWhenActorDies => context.become(waitingForDeath(sender))
}
def waitingForDeath(client: ActorRef): Receive = {
case Terminated(name) => client ! ActorDied
}
}
class Watched extends Actor {
override def receive: Receive = {
case _ => //do nothing
}
}
val finishedFuture = supervisor ? TellMeWhenActorDies
system.actorSelection("/user/$a/watched").tell(PoisonPill, supervisor)
Await.result(finishedFuture, 10 seconds)
Simply use the gracefulStop pattern. This is example is directly from the Akka docs:
try {
val stopped: Future[Boolean] = gracefulStop(actorRef, 5 seconds, Manager.Shutdown)
Await.result(stopped, 6 seconds)
// the actor has been stopped
} catch {
// the actor wasn't stopped within 5 seconds
case e: akka.pattern.AskTimeoutException =>
}

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.

How to periodically execute an AKKA Actor's routine?

I need an actor to stop one of its children, so that I can possibly create a new actor with same name (UUID ?).
I've got an ActorSystem with one Actor child. And this child creates new actors with context.actorOf and context.watch. When I try to stop one of these using context.stop, I observe that its postStop method is called as expected, but no matter how long I wait (seconds... minutes...), it never sends back the Terminated message to its creator (and watching) actor.
I read this in the AKKA documentation:
Since stopping an actor is asynchronous, you cannot immediately reuse the name of the child you just stopped; this will result in an InvalidActorNameException. Instead, watch the terminating actor and create its replacement in response to the Terminated message which will eventually arrive.
I don't care waiting for normal termination, but I really need actors to eventually terminate when asked to. Am I missing something ? Should I create actors directly from the system instead of from an actor ?
EDIT:
Here is my code :
object MyApp extends App {
def start() = {
val system = ActorSystem("MySystem")
val supervisor = system.actorOf(Supervisor.props(), name = "Supervisor")
}
override def main(args: Array[String]) {
start()
}
}
object Supervisor {
def props(): Props = Props(new Supervisor())
}
case class Supervisor() extends Actor {
private var actor: ActorRef = null
start()
def newActor(name: String): ActorRef = {
try {
actor = context.actorOf(MyActor.props(name), name)
context.watch(actor)
} catch {
case iane: InvalidActorNameException =>
println(name + " not terminated yet.")
null
}
}
def terminateActor() {
if (actor != null) context.stop(actor)
actor = null
}
def start() {
while (true) {
// do something
terminateActor()
newActor("new name possibly same name as a previously terminated one")
Thread.sleep(5000)
}
}
override def receive = {
case Terminated(x) => println("Received termination confirmation: " + x)
case _ => println("Unexpected message.")
}
override def postStop = {
println("Supervisor called postStop().")
}
}
object MyActor {
def props(name: String): Props = Props(new MyActor(name))
}
case class MyActor(name: String) extends Actor {
run()
def run() = {
// do something
}
override def receive = {
case _ => ()
}
override def postStop {
println(name + " called postStop().")
}
}
EDIT²: As mentionned by #DanGetz, one shall not need to call Thread.sleep in an AKKA actor. Here what I needed was a periodical routine. This can be done using the AKKA context scheduler. See: http://doc.akka.io/docs/akka/2.3.3/scala/howto.html#scheduling-periodic-messages . Instead I was blocking the actor in an infinite loop, preventing it to use its asynchronous mecanisms (messages). I changed the title since the problem was actually not involving actor termination.
It's hard to gauge exactly what you want now that the question has changed a bit, but I'm going to take a stab anyway. Below you will find a modified version of your code that shows both periodic scheduling of a task (one that kicks off the child termination process) and also watching a child and only creating a new one with the same name when we are sure the previous one has stopped. If you run the code below, every 5 seconds you should see it kill the child and wait for the termination message before stating a new one with the exact same name. I hope this is what you were looking for:
object Supervisor {
val ChildName = "foo"
def props(): Props = Props(new Supervisor())
case class TerminateChild(name:String)
}
case class Supervisor() extends Actor {
import Supervisor._
import scala.concurrent.duration._
import context._
//Start child upon creation of this actor
newActor(ChildName)
override def preStart = {
//Schedule regular job to run every 5 seconds
context.system.scheduler.schedule(5 seconds, 5 seconds, self, TerminateChild(ChildName))
}
def newActor(name: String): ActorRef = {
val child = context.actorOf(MyActor.props(name), name)
watch(child)
println(s"created child for name $name")
child
}
def terminateActor(name:String) = context.child(ChildName).foreach{ ref =>
println(s"terminating child for name $name")
context stop ref
}
override def receive = {
case TerminateChild(name) =>
terminateActor(name)
case Terminated(x) =>
println("Received termination confirmation: " + x)
newActor(ChildName)
case _ => println("Unexpected message.")
}
override def postStop = {
println("Supervisor called postStop().")
}
}