Search code examples
scalaakkaactor

Scala Akka actors - getting the state of an actor


The receive method defines an actor's behavior in Akka actors. I am looking for an approach that can give me all the different messages (and their types) an actor can process preferably at runtime in Scala.


Solution

  • Direct Answer

    Unfortunately the functionality that you are asking for is not available with akka. The receive method is defined as:

    type Receive = PartialFunction[Any, Unit]
    
    abstract def receive : Actor.Receive
    

    There is no way for a PartialFunction to enumerate all types that it can process. Further, once an Actor has been instantiated into an ActorRef you don't have access to the underlying receive method.

    One alternative is to define your receive outside of the Actor implementation and then use the isDefinedAt method of PartialFunction to test a particular value:

    object MyActor {
      val myPartial : Receive = {
        //receive functionality
      }
    }
    
    class MyActor extends Actor {
      override def receive : Receive = MyActor.myPartial
    }
    
    //test if a value can be processed by MyActor
    
    val testValue = 42
    
    val testValueIsDefined = MyActor.myPartial.isDefinedAt(testValue)
    

    Indirect Answer

    If you organize your code correctly then the foundation of your question becomes unnecessary.

    I've found a good practice is to strictly declare what types of inputs an Actor can receive:

    sealed trait MyActorInputs
    
    case class Foo(value : Int) extends MyActorInputs
    case class Bar(value : String) extends MyActorInputs
    
    object MyActor {
      val processInput : MyActorInput => Unit = ???
    }
    
    class MyActor extends Actor {
      override def receive : Receive = {
        case input : MyActorInput => 
          MyActor.processInput(input)
        case unknown => 
          System.error.println(s"MyActor received unknown input: $unknown")
      }
    }
    

    This technique does not provide compiler time checks or strict guarantees, but if you adopt it across all of your Actors then it tends to make life easier for bigger projects. It would also allow you to use reflection to dynamically get a list of available input types.