Edited answer for responding to missed points.
A General Approach
This approach is suggested for a more general usecase.
Q1: How we create actors out side of cluster dynamically?
You cannot directly create actors in other members in the cluster or outside. But However, you can implement member creation in your application logic. Then, you can subscribe for cluster membership events in a supervisor level actor. See the documentation
Assume you subscribed to MemberUp events to detect new members in cluster, and MemberRemoved events to detect offline members. So you can maintain a routing table in each actor system to communicate with other actor systems in your cluster.
cluster.subscribe(
getSelf(), ClusterEvent.initialStateAsEvents(),
ClusterEvent.MemberUp.class,
ClusterEvent.MemberRemoved.class );
Then you can receive get the member address from the membership events and implement other application logics. Checkout the following snippet for getting an idea.
@Override
public Receive createReceive() {
return receiveBuilder()
.match(ClusterEvent.MemberUp.class, memberUp -> {
// update routing table
// implement your logic when member is up
}).match(ClusterEvent.MemberRemoved.class, memberUp -> {
// update routing table
// implement your logic when member is up
}).build();
}
Q2: How we send messages to that actors and how that actors created across
cluster
Since you have the actor addresses in your routing table, you can use Akka remoting to send messages to them.
For more distributed methods to create and communicate with actors dynamically in a cluster, you can use Cluster Singleton and/or Cluster Sharding.
Cluster Singleton
If your cluster needs only one specific type of actor in the cluster, you can create a Cluster Singleton This actor will be always available/running somewhere in the cluster irrespective of how many members are in cluster.
Q1: How we create actors out side of cluster dynamically?
You can create a singleton actor, and it will be dynamically available in your cluster. If the cluster member running your singleton actor is stopped, cluster will spawn another singleton actor somewhere in the cluster.
on every node in the cluster, or every node with a given role, use the
ClusterSingleton extension to spawn the singleton.
// From the docs
ClusterSingleton singleton = ClusterSingleton.get(system);
// Start if needed and provide a proxy to a named singleton
ActorRef<Counter.Command> proxy =
singleton.init(SingletonActor.of(Counter.create(), "GlobalCounter"));
Q2: How we send messages to that actors and how that actors created across
cluster
Use the proxy reference to send messages to the singleton.
proxy.tell(Counter.Increment.INSTANCE);
Cluster Sharding
From the docs,
Cluster sharding is useful when you need to distribute actors across
several nodes in the cluster and want to be able to interact with them
using their logical identifier, but without having to care about their
physical location in the cluster, which might also change over time.
Q1: How we create actors out side of cluster dynamically?
Cluster sharding init should be called on every node for each entity
type. Which nodes entity actors are created on can be controlled with
roles. init will create a ShardRegion or a proxy depending on whether
the node’s role matches the entity’s role.
EntityTypeKey<Counter.Command> typeKey = EntityTypeKey.create(Counter.Command.class, "Counter");
ActorRef<ShardingEnvelope<Counter.Command>> shardRegion =
sharding.init(Entity.of(typeKey, ctx -> Counter.create(ctx.getEntityId())));
Q2: How we send messages to that actors and how that actors created across
cluster
Messages to a specific entity are then sent via an EntityRef. The
entityId and the name of the Entity’s key can be retrieved from the
EntityRef. It is also possible to wrap methods in a ShardingEnvelope
or define extractor functions and send messages directly to the shard
region.
EntityRef<Counter.Command> counterOne = sharding.entityRefFor(typeKey, "counter-1");
counterOne.tell(Counter.Increment.INSTANCE);
shardRegion.tell(new ShardingEnvelope<>("counter-1", Counter.Increment.INSTANCE));
You may define the number of shards in the actor system configuration. Note that this value should be same for all actor systems in the cluster, and changing this value will require cluster wide restart.
akka.cluster.sharding {
# Number of shards used by the default HashCodeMessageExtractor
# when no other message extractor is defined. This value must be
# the same for all nodes in the cluster and that is verified by
# configuration check when joining. Changing the value requires
# stopping all nodes in the cluster.
number-of-shards = 1000
}
Q2: How we send messages to that actors and how that actors created across
cluster
Alternatively, You can use Cluster Client to send messages to actors in a cluster, from outside the cluster.
I strongly suggest you to read the documentation since these are some deep topics in Akka Clustering.