Access the messages of actor mailbox - akka

I want to read the messages in ShardRegions mailbox. In previous akka version, we could use the following code to get only the size of mailbox:
getContext().getMailboxSize();
Is there any way to fetch the type of messages in the mailbox?

Here is the solution
Define a wrapper mailbox for shard region like this:
class UnboundedMailboxWrapper extends MailboxType with ProducesMessageQueue[UnboundedMailboxWrapper.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new UnboundedMailboxWrapper.MessageQueue
}
object UnboundedMailboxWrapper {
class MessageQueue extends ConcurrentLinkedQueue[Envelope] with UnboundedQueueBasedMessageQueue {
val runtime = RuntimeManager.runtime
final def queue: Queue[Envelope] = this
override def enqueue(receiver: ActorRef, handle: Envelope): Unit = {
runtime.queue.add(handle)
queue add handle
}
override def dequeue(): Envelope = {
if (!runtime.queue.isEmpty) runtime.mailbox.queue.poll()
queue.poll()
}
}
}
in this mailbox we duplicate the element which added, to another queue, so when calculate size and other operation on it, there is no any impact on performance of mailbox queue
In duplicated queue we can calculate the number of messages and sort them:
def getElemets(): String = {
runtime.queue.asScala.toList.groupBy(_.message.getClass.getName)
.map(e ⇒ (e._1, e._2.length)).toSeq
.sortBy(_._2).foldLeft("") { (a, b) ⇒
b._1 + ":" + b._2 + "\n" + a
}
}
and with JMX or any other way we can call this method in runtime
and finlally assign this mailbox to ShardRegion dispatcher:
monit-dispatcher {
mailbox-type = "im.actor.server.cluster.UnboundedMailboxWrapper"
}
akka.cluster.sharding {
use-dispatcher = "monit-dispatcher"
}

Related

Does Akka Decider have access to the full failure scenario?

New to Akka. Creating a new Scala class that extends SupervisorStrategy gives me the following template to work with:
class MySupervisorStrategy extends SupervisorStrategy {
override def decider: Decider = ???
override def handleChildTerminated(context: ActorContext, child: ActorRef,
children: Iterable[ActorRef]): Unit = ???
override def processFailure(context: ActorContext, restart: Boolean,
child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = ???
}
I'm looking for a way to access:
The Throwable/Exception that was thrown from the child actor
The child actor ActorRef that threw the exception
The message that was passed to the child actor that prompted the exception to be thrown
I think the Decider (which is actually a PartialFunction[Throwable,Directive]) gets passed the Throwable whenever the child throws the exception, but I'm not seeing where I could get access to #2 and #3 from my list above. Any ideas?
Update
From the posted fiddle, it looks like a valid Decider is:
{
case ActorException(ref,t,"stop") =>
println(s"Received 'stop' from ${ref}")
Stop
case ActorException(ref,t,"restart") =>
println(s"Received 'restart' from ${ref}")
Restart
case ActorException(ref,t,"resume") =>
println(s"Received 'resume' from ${ref}")
Resume
}
Above, I see all three:
The exception that was thrown by the child
The child (ref) that threw the exception
The message that was sent to the child originally (that caused the exception to be thrown)
It looks like there's nothing in that Decider that needs to be defined inside that Supervisor class. I'd like to pull the Decider logic out into, say, MyDecider.scala and find a way to refactor the Supervisor so that its supervisorStrategy uses an instance of MyDecider, so maybe something similar to:
class Supervisor extends Actor {
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._
var child: ActorRef = _
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute, decider = myDecider)
...
}
For #2 you could access the sender "if the strategy is declared inside the supervising actor"
If the strategy is declared inside the supervising actor (as opposed to within a companion object) its decider has access to all internal state of the actor in a thread-safe fashion, including obtaining a reference to the currently failed child (available as the sender of the failure message).
The message is not made available so the only option is to catch your exception and throw a custom one with the message that was received.
Here is a quick fiddle
class ActorSO extends Actor {
def _receive: Receive = {
case e =>
println(e)
throw new RuntimeException(e.toString)
}
final def receive = {
case any => try {
_receive(any)
}
catch {
case t:Throwable => throw new ActorException(self,t,any)
}
}
}
Update
A Decider is just a PartialFunction so you can pass it in the constructor.
object SupervisorActor {
def props(decider: Decider) = Props(new SupervisorActor(decider))
}
class SupervisorActor(decider: Decider) extends Actor {
override val supervisorStrategy = OneForOneStrategy()(decider)
override def receive: Receive = ???
}
class MyDecider extends Decider {
override def isDefinedAt(x: Throwable): Boolean = true
override def apply(v1: Throwable): SupervisorStrategy.Directive = {
case t:ActorException => Restart
case notmatched => SupervisorStrategy.defaultDecider.apply(notmatched)
}
}
object Test {
val myDecider: Decider = {
case t:ActorException => Restart
case notmatched => SupervisorStrategy.defaultDecider.apply(notmatched)
}
val myDecider2 = new MyDecider()
val system = ActorSystem("stackoverflow")
val supervisor = system.actorOf(SupervisorActor.props(myDecider))
val supervisor2 = system.actorOf(SupervisorActor.props(myDecider2))
}
By doing so, you won't be able to access supervisor state like the ActorRef of the child that throw the exception via sender() (although we are including this in the ActorException)
Regarding your original question of accessing from the supervisor the child message that cause the exception, you can see here (from akka 2.5.3) that the akka developers choose to not make it available for decision.
final protected def handleFailure(f: Failed): Unit = {
// ¡¡¡ currentMessage.message is the one that cause the exception !!!
currentMessage = Envelope(f, f.child, system)
getChildByRef(f.child) match {
/*
* only act upon the failure, if it comes from a currently known child;
* the UID protects against reception of a Failed from a child which was
* killed in preRestart and re-created in postRestart
*/
case Some(stats) if stats.uid == f.uid ⇒
// ¡¡¡ currentMessage.message is not passed to the handleFailure !!!
if (!actor.supervisorStrategy.handleFailure(this, f.child, f.cause, stats, getAllChildStats)) throw f.cause
case Some(stats) ⇒
publish(Debug(self.path.toString, clazz(actor),
"dropping Failed(" + f.cause + ") from old child " + f.child + " (uid=" + stats.uid + " != " + f.uid + ")"))
case None ⇒
publish(Debug(self.path.toString, clazz(actor), "dropping Failed(" + f.cause + ") from unknown child " + f.child))
}
}

How to send Akka broadcast message

I'm trying to send a single message to several actors. Investigation led me to the code below, but it doesn't work. The message that's "wrapped" in the Broadcast object disappears, and the plain string ends up in the dead letter box.
Can someone tell me what I'm missing? (Edit: I've added the correction below)
import akka.actor.{Actor, ActorSystem, Props}
import akka.routing.{Broadcast, BroadcastRoutingLogic, Router}
object RouterAndBroadcast {
class MyRoutee extends Actor {
override def receive: Receive = {
case x => println(s"MyRoutee $this got message $x")
}
}
def main(args: Array[String]): Unit = {
val system = ActorSystem.create("system")
val mr0 = system.actorOf(Props[MyRoutee])
val mr1 = system.actorOf(Props[MyRoutee])
val mr2 = system.actorOf(Props[MyRoutee])
/* This was the error:
val router = new Router(BroadcastRoutingLogic())
router.addRoutee(mr1)
router.addRoutee(mr2) */
// This is the corrected version:
val router = new Router(BroadcastRoutingLogic())
.addRoutee(mr1)
.addRoutee(mr2)
mr1 ! "Hello number one!"
mr2 ! "Ahoy two, me old mate!"
router.route(new Broadcast("Listen up!"), mr0) // vanishes??
router.route("Listen up!", mr0) // ends up in dead letters
mr1 ! "Number one, are you still there?"
mr2 ! "Two, where's the grog?"
router.route(new Broadcast("Still shouting!"), mr0) // also vanishes
Thread.sleep(5000)
system.terminate()
}
}
Router.addRoutee returns a copy with the routee added, it doesn't modify ther Router in place, see:
https://github.com/akka/akka/blob/b94e064a34a7f6a9d1fea55317d5676731ac0778/akka-actor/src/main/scala/akka/routing/Router.scala#L140
/**
* Create a new instance with one more routee and the same [[RoutingLogic]].
*/
def addRoutee(routee: Routee): Router = copy(routees = routees :+ routee)
so instead try
router = router.addRoutee(mr1).addRoutee(mr2)

Akka: context become throws NullPointerException?

I have a pretty simple actor defined as:
object CoreActor extends Actor with ActorLogging {
// val SYSTEM_NAME = "CoreActors"
val system = Akka.system()
// val system = ActorSystem.create("push", ConfigFactory.load.getConfig("push"))
val pushUri = Play.current.configuration.getString("pushservice.uri").getOrElse("akka.tcp://CentralappPush#127.0.0.1:5000")
val protocol = Play.current.configuration.getString("pushservice.protocol").getOrElse("akka.tcp")
val pushSystem = Play.current.configuration.getString("pushservice.system").getOrElse("CentralappPush")
val ip = Play.current.configuration.getString("pushservice.ip").getOrElse("127.0.0.1")
val port = Play.current.configuration.getInt("pushservice.port").getOrElse(5000)
val rootPath = Play.current.configuration.getString("pushservice.path.root").getOrElse("user")
val actorPath = Play.current.configuration.getString("pushservice.path.actor").getOrElse("PushMaster")
val selectionPath = RootActorPath(new Address(protocol, pushSystem, ip, port)) / rootPath / actorPath
val pushActor = context.actorSelection(selectionPath)
def receive = {
case pprs: List[PlaceProvider] => {
log.info("I received something")
pushActor ! pprs.map(_.clone)
context become afterSend
}
}
def afterSend: Receive = {
case pprs: List[PlaceProvider] => {
pprs.foreach(_.update) // update in the db
context.stop(self)
}
case _ => {
log.info("Did not understand message")
context.stop(self)
}
}
}
The actors are created with unique names from within a controller in the Play! framework. What I'm seeing is that when an actor is created for the first time of a place update, it does it's job and goes into the shutting down context as expected. A second call to the same action within the play framework causes this:
[ERROR] [02/18/2015 12:32:46.181] [application-akka.actor.default-dispatcher-2] [akka://application/user/OlD1vFKVLn1424259166159] null
java.lang.NullPointerException
at actors.CoreActor$$anonfun$receive$1.applyOrElse(CoreActor.scala:29)
at akka.actor.Actor$class.aroundReceive(Actor.scala:465)
at actors.CoreActor$.aroundReceive(CoreActor.scala:11)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
at akka.actor.ActorCell.invoke(ActorCell.scala:487)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:238)
at akka.dispatch.Mailbox.run(Mailbox.scala:220)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Which is quite baffling. Why does that happen? Why does it happen only during the second time an actor of the same type is started?
You actor is an object - this enforces that there is a single instance of the actor. When an actor is stopped it will go through some processing to cleanup its resources. Since on your next request you try to re-create a new actor using the same instance the creation is failing.
Try changing it to a class.
class CoreActor extends Actor with ActorLogging {
}

Akka Actors logging processing time

I have a set of Akka Actors and I give about a couple of hundreds of messages to each one of them. I want to track how much time each instance of that Actor took to process all the messages that it received. What I'm doing currently is to have a state in the Actor instance as:
var startTime
var firstCall
I set both the variables when the Actor instance is first called. Is there another way that I could use to track the processing time for my Actor instances? I want to avoid having a local state in my Actor instance.
This is a good use case for context.become.
Remember than a receive block in an Akka actor is just a PartialFunction[Any, Unit], so we can wrap that in another partial function. This is the same approach taken by Akka's builtin LoggingReceive.
class TimingReceive(r: Receive, totalTime: Long)(implicit ctx: ActorContext) extends Receive {
def isDefinedAt(o: Any): Boolean = {
r.isDefinedAt(o)
}
def apply(o: Any): Unit = {
val startTime = System.nanoTime
r(o)
val newTotal = totalTime + (System.nanoTime - startTime)
log.debug("Total time so far: " + totalTime + " nanoseconds")
ctx.become(new TimingReceive(r, newTotal))
}
}
object TimingReceive {
def apply(r: Receive)(implicit ctx: ActorContext): Receive = new TimingReceive(r, 0)
}
Then you can use it like this:
class FooActor extends Actor {
def receive = TimingReceive {
case x: String => println("got " + x)
}
}
After each message, the actor will log the time taken so far. Of course, if you want to do something else with that variable, you'll have to adapt this.
This approach doesn't measure the time the actor is alive of course, only the time taken to actually process messages. Nor will it be accurate if your receive function creates a future.

Terminating a flailing akka actor

I have the following actor setup, using Akka actors (2.10)
A -spawn-> B -spawn-> C
A -sendWork-> B -sendWork-> C
C -sendResults-> A (repeatedly)
However, at some point A notices that it should change the workload sent to B/C because C is sending a large number of messages that turn out to be useless. However, in such situations C's inbox seems to be very full, and/or C may be blocked.
How can A tell B to shutdown C immediately? Losing the state and messages of both B and C is acceptable, so destroying them and spawning new ones is an option.
Given the actors are started the way you described, then using stop in the right way will do what you require. According to the docs, calling stop will both:
1) stop additional messages from going into the mailbox (sent to deadletter)
2) take the current contents of the mailbox and also ship that to deadletter (although this is based on mailbox impl, but the point is they won't be processed)
Now if the actor will need to completely finish the message it's currently processing before it's all the way stopped, so if it's "stuck", stopping (or anything for that matter) won't fix that, but I don't think that's the situation you are describing.
I pulled a little code sample together to demonstrate. Basically, A will send a message to B to start sending work to C. B will flood C with some work and C will send the results of that work back to A. When a certain number of responses have been received by A, it will trigger a stop of B and C by stopping B. When B is completely stopped, it will then restart the process over again, up to 2 total times because it stops itself. The code looks like this:
case object StartWork
case class DoWork(i:Int, a:ActorRef)
case class WorkResults(i:Int)
class ActorA extends Actor{
import context._
var responseCount = 0
var restarts = 0
def receive = startingWork
def startingWork:Receive = {
case sw # StartWork =>
val myb = actorOf(Props[ActorB])
myb ! sw
become(waitingForResponses(myb))
}
def waitingForResponses(myb:ActorRef):Receive = {
case WorkResults(i) =>
println(s"Got back work results: $i")
responseCount += 1
if (responseCount > 200){
println("Got too many responses, terminating children and starting again")
watch(myb)
stop(myb)
become(waitingForDeath)
}
}
def waitingForDeath:Receive = {
case Terminated(ref) =>
restarts += 1
if (restarts <= 2){
println("children terminated, starting work again")
responseCount = 0
become(startingWork)
self ! StartWork
}
else{
println("too many restarts, stopping self")
context.stop(self)
}
}
}
class ActorB extends Actor{
import concurrent.duration._
import context._
var sched:Option[Cancellable] = None
override def postStop = {
println("stopping b")
sched foreach (_.cancel)
}
def receive = starting
def starting:Receive = {
case sw # StartWork =>
val myc = context.actorOf(Props[ActorC])
sched = Some(context.system.scheduler.schedule(1 second, 1 second, self, "tick"))
become(sendingWork(myc, sender))
}
def sendingWork(myc:ActorRef, a:ActorRef):Receive = {
case "tick" =>
for(j <- 1 until 1000) myc ! DoWork(j, a)
}
}
class ActorC extends Actor{
override def postStop = {
println("stopping c")
}
def receive = {
case DoWork(i, a) =>
a ! WorkResults(i)
}
}
It's a little rough around the edges, but it should show the point that cascading the stop from B through to C will stop C from sending responses back to A even though it still had messages in the mailbox. I hope this is what you were looking for.