Reputation: 408
I am writing plugins for a C# Desktop application (not a server but a Desktop GUI application). To make our threading issues simpler I am researching if I can employ AKKA.NET inside of these plugins. The plugins are principally independend from each other. Thus from an architecture POV, it is natural to give each plugin it's own "private" ActorSystem instance. The advantage of this approach is that the plugins are maximally isolated from each other. On the other side, I have read some articles about Akka for the JVM which tell me that having too many ActorSystem instances in an application is an anti pattern because an ActorSystem is quite heavyweight.
A realistic number of concurrent plugins is 10-20, i.e. the appliction could then have at worst 20 ActorSystem instances running inside. Again, this is a GUI desktop application, which is often run in terminal server sessions (i.e. there may be many of these GUI applications running on a terminal server).
So - is this simplicistic approach (one ActorSystem per library) tenable? Or is it better to devise an approach using a global ActorSystem, which uses per-plugin top-level actors to isolate the plugins. This approach is probably better for performance, but I am a bit concerned about it because the plugins are not as isolated from each other.
So - is this "multiple-system" approach a good architectural approach, or is it better to stick with the "one global system" design? What are your experiences here?
Upvotes: 3
Views: 878
Reputation: 8394
So - is this simplicistic approach (one ActorSystem per library) tenable? Or is it better to devise an approach using a global ActorSystem, which uses per-plugin top-level actors to isolate the plugins. This approach is probably better for performance, but I am a bit concerned about it because the plugins are not as isolated from each other.
This is the approach I'd go with - have each plugin create its own hierarchy of actors using the same ActorSystem
. Each plugin can have its own actor and message types with no overlap. If you ended up running multiple ActorSystem
s you'd still end up having multiple actors all using the same threads, because by default the ActorSystem
schedules actors onto the same .NET Thread Pool that the TPL and other parts of your desktop application might use. Having one ActorSystem
manage all of that might be easiest since that way you have a single dispatcher marshalling the execution on the same group of threads (less competition.)
Upvotes: 5
Reputation: 7542
If isolation is your goal, then multiple actor systems won't solve your issue - ActorSystem
is just an ordinary class, you still can share the data using i.e. static fields, and (probably) you can still access other actor systems if you are determined enough. Therefore actor system won't help you if you run untrusted code.
True in-process isolation in .NET could be achieved by using AppDomains in old .NET Framework or AssemblyLoadContext in .NET Core.
Keep in mind, that using actor programming paradigm is serious design decision and component isolation can be achieved in many ways. So if component isolation is the only reason, why you decided on using actors, you may want to look out and reconsider other options.
You can use actor per plugin, or even use native Akka.NET extensions - this is mechanism that allows us to build plugins for the akka itself. Almost every higher level feature of Akka is built as an extension: cluster, remoting, cluster sharding, persistence etc.
To build an extension you need two classes:
public class MyExtensionProvider : ExtensionIdProvider<MyExtension>
{
public override MyExtension CreateExtension(ExtendedActorSystem system) =>
new MyExtension(system);
}
public class MyExtension : IExtension
{
public MyExtension(ExtendedActorSystem system) { }
}
You can register and retrieve those extensions from code itself via: actorSystem.WithExtension<MyExtension, MyExtensionProvider>()
(checkout overrides of that method too). You can also register them directly in HOCON - this way when provided via HOCON config, they will be started automatically on system start:
akka.extensions = [
"MyNamespace.MyExtensionProvider1, MyAssembly",
"MyNamespace.MyExtensionProvider2, MyAssembly"
]
Upvotes: 3