0
votes

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.

1

1 Answers

4
votes

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.