Reputation: 1901
Is it possible to bind a set of AKKA actors to a certain context?
E.g. I have three actors and each of them are implementing a state machine. These actors send messages to each other on certain state transitions. Now I want to bind these state to a context, e.g. a user context. So I have a user (represented by an userId) who has a set of actors bound in certain states. As long as this user context exists these actors (or at least their states) must be bound to the user's context. Is this possible per se in AKKA or do I have to persist the state of the different actors user-wise? Or are actors not designed for these use cases?
Upvotes: 0
Views: 1675
Reputation: 35443
I'm not 100% sure that I get what you are asking, but I'll take a shot at an answer anyway. The actor system itself is heirarchical. Parent/child relationships exist in the heirarchy and the parent will be the owner (and supervisor) to the children. If you modeled your system with a UserContext
actor being the parent to three child actors (your FSM actors) then I suppose the children will be bound to this UserContext
actor instance. Consider this simplified example model:
class UserContext extends Actor{
val stateA = context.actorOf(Props[StateA])
val stateB = context.actorOf(Props[StateB])
val stateC = context.actorOf(Props[StateC])
def receive = {
case _ =>
}
}
class StateA extends Actor{
def receive = {
case _ =>
}
}
class StateB extends Actor{
def receive = {
case _ =>
}
}
class StateC extends Actor{
def receive = {
case _ =>
}
}
If you set things up this way, the state children will be started up when this user context instance is created and will also be stopped when the user context instance is stopped. Now all you need is a little code to make sure only one user context per user exists in the system. You could do something like this to assure that:
object UserContext{
def apply(username:String)(implicit system:ActorSystem):ActorRef = {
val ctx = system.actorFor("/user/" + username)
if (ctx.isTerminated){
try{
system.actorOf(Props[UserContext], username)
}
catch{
case InvalidActorNameException(msg) if msg.contains("unique") => apply(username)
}
}
else
ctx
}
}
This factory object makes sure the user context actor for the supplied username is not currently running. If it is, it just returns that ref. If not, it starts it up and binds it to the name of the user for later lookups.
Once you do things like this, just use the factory to lookup the UserContext
for a supplied username and then route all messages through it and let it delegate messages to the correct child state actor. This is obviously quite simplified, but I think it might be something similar to what you want.
Upvotes: 3