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