I have an akka-http api that, upon receiving requests, sends messages to my Cluster via the cluster sharding region. The API layer doesn’t know the ActorRefs of the actors in question, just the string identifiers.
region ! AddTarget(sourceId, targetId)
So Cluster Sharding works by looking up or creating the appropriate actor identified by “sourceId”, passing “targetId” as an additional parameter.
Each actor can have many targets - they’ll all be talking to each other.
From within the source actor, I’m faced with the choice of storing those targets as List[String] or List[ActorRef].
If I stick with List[String], I can use context.parent to send the message to the targets, through the region.
If I use List[ActorRef] instead (presumably by doing a one time Identify exchange so I can get the ActorRef from the response’s sender()), I’d be able to skip the region lookup on all ensuing communications.
Is one a best practice, or clearly better than the other?
If a sharded actor needs to send a message to another sharded actor (in the same cluster), I believe the region is safer than the ActorRef, because the actor might be passivated. If passivated, the ActorRef won’t work anymore, while the region will still be able to find it. Is this correct?
The other question is how the sharded actor would communicate with the region. I believe context.parent is the parent Shard, not the actual ShardRegion. So it’s best to either have the region assigned to the actor via a message, or just use ClusterSharding(context.system).shardRegion("<name>"). Assuming I’m not overlooking an easier way for a sharded actor to refer to its own ShardRegion?
You conclusions are correct. Send via the region, and get the region ActorRef via the ClusterSharding extension. The latter can be done once in the constructor of the source actors.
The region ActorRef can also be passed in as a constructor parameter via the Props, and that can be useful for unit testing. Replacing the region with a TestProbe.