5

lets say i have the following Actor hierarchy :

user
|____A___|---E
|        |---F
|        |---G
|
|____B___I
|____C___J
|____D___K

Lets say Actor E Needs to have IActorRef's of Actors I,J,K, passing the Actor Ref's in the constructor gets messy if the the system scales and needs more Actors , and user ActorSelection not advised to use locally.

is there A proper and dynamic way of getting ActorRef's as the system scales?

i have thought a lot about whether i should ask this question or not as it can interpreted as opinion based question , but im really strugling with this problem as i have searched a lot and it is not yet clear what is the best practice to this problem as the code can get really messy and unreadable in time.

Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54
ezio
  • 359
  • 2
  • 13
  • The way you described the question and the problem at first feels to me like it's "opinion-based" (thus risking being closed). I don't know akka.net, but I can understand from the text what's the actual problem, and I think there may be one or two definitive solutions, and that other people also struggled with this problem. I can't think of any way to improve the wording to minimize the "opinion-based" feeling I got at first. If anyone reading this has - please share and help improve this question. Maybe focusing on ActorSelection not recommended? Maybe change title to "too many IActorRefs"? – quetzalcoatl Aug 13 '20 at 16:07
  • I still don't know akka.net :) but the problem looks like a typical inversion-of-control problem with too many dependencies. Sometimes it's hard to get away from having too many, and there are some common ways of mitigating the effects - like, if you have absolutely-needed-pack-of-dependencies, collect them into another object and pull that object from the container instead. Now you've got 1 ctor param instead of 10, and so on. Also, many IoCCs allow to resolve multiple matches like `myctor(Dependency1 dep1, Dependency2[] deps2)` note the array. Maybe that's the ActorSelection, no idea. – quetzalcoatl Aug 13 '20 at 16:13
  • 1
    @quetzalcoatl i have thought about as opinion based too a lot but its still unclear what the best practices are morever it can lead to messy unreadable code quickly, i'll update the question , and thank you for your proposal i did not think of it of the way of IOC problem, thank you sir ! – ezio Aug 13 '20 at 17:18
  • How many actors do you need to allocate in a single ActorSystem cluster ? I've had 100-200 actors allocated locally and interconnect with no issues. Maybe your issue is bad performance of the ActorSelection search ? If you address actors locally, there is no need to use ActorSelection search. Common practice in clusters is to use subscription: at the time your actor connects to the cluster, use a mechanism (pubsub is an easy option) to share/handshake the new identity with the existing actors. Doing so, actors can register ActorRefs for actors they need to contact. – Goodies Aug 13 '20 at 17:39
  • @Goodies the problem is not in the performance, its managing the IActorRefs , when the system gets bigger with different actors , not with the same roles for example when said 200 actors the creation most of them are created from one simple Actor, otherwise its insane to have 200 different Actors in one application (at least that what i guess) – ezio Aug 13 '20 at 17:52
  • Why do you need to pass multiple ActorRefs to constructors ? Again, good practice in clusters is to connect to the cluster (ActorSystem).. and start talking around: set up a pubsub and emit your Identity: could be IActorRef+Rolestring, as long as you stay inside the same ActorSystem. Other subscribers will pick up your identity and store it as needed. Through the same pubsub, you'll also get the IActorRefs you need in response, and the other cluster nodes know you exist. When your cluster is heterogeneous (different actors) you keep these handles selectively. Not all connections are needed. – Goodies Aug 13 '20 at 18:25
  • No room in the comments for more editing.. I've tried to provide an Answer. See below. – Goodies Aug 13 '20 at 18:38

2 Answers2

2

Just start sending messages, instead of trying to pre-configure Actors with (many) other Actors. It makes initialisation complicated indeed, when there are many different Actors. Also: you cannot regard IActorRef handles passed to a constructor as static and eternally valid: when an Actor goes offline, you need a mechanism to detect that and null its handle, or delete it. The other Actors in the cluster need to watch Akka log messages.. which are not guaranteed.. etc..

Instead: when you connect a new Actor to the cluster, emit (push) your Identity through a pubsub. Your new Actor message could be: ActorSytem.Name+IActorRef+RoleString.

https://getakka.net/articles/clustering/distributed-publish-subscribe.html

The RoleString is a descriptor for the task of your Actor. Other actors can decide to register your IActorRef, based upon RoleString.

In the process, other subscribers (Actors) to the pubsub will pick up your identity and store your identity. Then, they emit their identity in the same way, through the same pubsub. As a result, you'll receive the RoleString identities you need in responses.. and the other cluster nodes (Actors) know you exist.

When the Actor needs to disconnect, emit a pubsub message first, before actually disconnecting the Actor from the Cluster. Doing so, other actors know the Actor went off line.

One pitfall with this strategy: preventing endless pubsub loops (I/O avalange). Solution I use: prevent an Actor from sending too many messages by testing the time since its previous pubsub message. Put e.g. 1 message per minute, regardless of other Actors.. this will result in a heartbeat, rather than an avalange of messages. And you'll be informed in regular intervals of the online status of all Actors. An exit/offline message is not needed in this case.

Goodies
  • 1,951
  • 21
  • 26
  • this is a great answer , although i did not say that im using a cluster anywhere in my system not im intending to do so, so my question is how can manage them locally , and by the way , that was a brilliant explanation you have provided – ezio Aug 13 '20 at 19:40
  • Thx ezio.. can you vote it up please ? wished I could show you some tested code, but I guess my employer would not appreciate if I put it up. It can be quite small, though. btw the reference I put is an invaluable resource about akka.net, I learned a lot of it. – Goodies Aug 13 '20 at 20:29
  • well you can give me an idea about how does the pattern look like , i mean i can for example tell you about the best practices in c# but i wont be showing you or giving you any advantages of you over me – ezio Aug 13 '20 at 21:28
0

So i looked up The documentation And read it thoroughly and i found that there are Two ways of obtaining IActorRef's in a clean way.

The default way is Is to Use ActorSelection and wait for a reply, From that Reply you use The Sender property and store the IactorRef . You can Use The builtIn MessageIdentify, once sent to an actor the Receiver will automatically reply with ActorIdentity Message containing IActorRef

A complete example can be found here

ezio
  • 359
  • 2
  • 13
  • With an identification message on Actor Join and a Close message on Actor terminate like I explained you can avoid repeated slow actions on every command like ActorSelection(). This is what is normally done in cluster systems, Akka is designed for cluster systems. – Goodies Aug 20 '20 at 08:35