I have a scenario where I need to provide a Behavior of a specific type. This Behavior also needs to handle events that are published on the Event Stream. So say the specific type is:
case class DoSomething(i: Int)
and I then need to implement a function to return a Behavior to handle this type of message:
def foo(): Behavior[DoSomething]
I then also need to handle the following message on the event stream:
case class PublishedEvent(str: String)
The only solution I came up with was to spawn another actor from within my DoSomething behavior and then forward messages to it:
sealed trait Command
case class Command1(str: String) extends Command
case class Command2(str: String) extends Command
def foo(): Behavior[DoSomething] = Behaviors.setup { context =>
val actor = context.spawnAnonymous[Command](Behaviors.setup { context =>
context.system.eventStream ! EventStream.Subscribe(context.messageAdapter {
case PublishedEvent(str) => Command2(str)
})
Behaviors.receiveMessage {
case Command1(str) =>
println("Received Command1: " + str)
Behaviors.same
case Command2(str) =>
println("Received Command1: " + str)
Behaviors.same
}
})
Behaviors.receiveMessage {
case DoSomething(i) =>
actor ! Command1(i.toString)
Behaviors.same
}
}
My question is is there any means of avoiding spawning a new actor and doing it all from within the same actor? i.e. Is there a way I can map a Behavior[Command] to a Behavior[DoSomething]?
I also have this problem regularly and the best solution I found is to use the
narrow[...]method on a common "superBehavior" to narrow down on a message type a client is supposed to send to the respective actor. It is possible to combine the handling of both message types in oneBehaviorby defining a common interface (in scala of course atrait):Now, if you want to pass a
Behavior[DoSomething]to a client, you can simply obtain it like this:You can keep the
Commandtrait private to your current context, but I think you will have to expose at least the common super trait to the outside world. With union types as they will be available in Scala 3 this can be avoided and you won't need the artificial super trait.