The Act in Modern Age
The word “Act” has a lot of meaning. The one we intend to use in this article is performance as in acting a role or persona at least in this introductory section. In modern times pervasive social media have anchored eyeballs 24x7 on performing artists or simply; “actors”. This has carved a mark on their personas. They now need to wear the act of their upcoming movie or series much longer than in the past days.
But then, this article is not about the method, phenomena, or life of actors and their acting. This is meant to be an article that takes a creative jab at a software programming topic. If you have survived enough in the industry, you would have got the cue (wink, wink). We are talking about the Actor design pattern.
Our copy director (the one responsible for this article!) has warned us and also washed our hands off the responsibility of this article because of our poor attempt at humour. But we thought it was worth a shot as software programmers have spent enough time in front of screens that the advancements of humour standards in stand-up performances are oblivious.
Much oblivious; compared to the advancements in the start-up landscape.
Alright, enough of jostling each other on this, let us get to the business and talk about Actors in Orleans (not the French “isle” within the bustling US of A).
Microsoft claims to have dug gold. They invented a virtual actor design pattern where the actor will have a life, longer than its run time. Perhaps without a performance penalty! Before we virtualise let us recap the Actor design pattern itself.
The actor
It is a thread-safe unit that can have a state of computation. It is capable of generating, and consuming messages. It can create new actors when needed. This was all in fashion in the early days of Object-Oriented programming. It lost its shine as time progressed. Over time, behaviour was introduced. It is a function that processes incoming messages. An Actor could specify a new behaviour for the message that it emits. Though the chrome of this design pattern lost its shine to new languages; the design pattern itself survived in those new languages just to be rediscovered.
Orleans
It is the distributed compute native framework that addresses the modern distributed application build challenges. Orleans builds upon the Actor design pattern and claims to have discovered the Virtual Actor design pattern. Along the way, the two simple concepts were introduced.
Grain
They are composites of identity, behaviour and state optionally. Identity gives the longevity to actors. This is; a contributing factor to the “Virtual” in virtual actor design pattern. The other contributing factor is the nature of the state. Grain can have a persistent or volatile state. This gives way for the framework to call for a grain when required. It is done based on their identity. They are removed from the memory when not needed.
Silo
The negative commotion that emerges on hearing this word is beyond description. Yet framework designers used this name for a concept in Orleans. They are equivalent to runtime. They can be grouped to create clusters. Clusters of runtimes host grain.
At this point, it is “virtually” impossible for us not to quote Kubernetes. The concepts in Orleans have a strange recall to those in the Kubernetes framework.
Expressing ourselves through code
Let us start Grain, since C# does not allow inheritance from multiple classes, we ought to go the Interface and Base class way. Something that is not an alien concept to you; isn’t it?
namespace Contracts;
public interface IGreet: IGrainWithIntegerKey {
ValueTask<string> SimpleGreeting();
}
Next, we implement this contract in a class.
using Contracts;
public class GreetGrain: Grain, IGreet {
ValueTask<string> IGreet.SimpleGreeting() {
return ValueTask<string>.FromResult(“I am a long running performer. Greetings to you, Thank you for instantiating me!”);
}
Recommended by LinkedIn
}
Notice the return types. Modern digital native applications cannot assume they will run on a console by default. Thus, it is better to return a value; instead of printing a greeting message on the console. We cannot run this yet. We need to give a silo for this grain to run in.
using Microsoft.Extensions.Hosting;
namespace Silo.Console {
IHostBuilder builder = Host.CreateDefaultBuilder(args).UseOrleans(silo => silo.UseLocalhostClustering()).UseConsoleLifetime();
using IHost host = builder.Build();
await host.RunAsync();
}
We are using C# 9.0+ syntax where the boilerplate code for static void main is unnecessary. Well; we cannot yet experience the Orleans in action. Though, we can run it. The result will be, a console application that waits for some action.
We ought to add a client that gets the greetings. It is in the client that we will instantiate a grain and use the services of Silo.
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Contracts;
namespace Actor.Client {
IHostBuilder builder = Host.CreateDefaultBuilder(args).UseOrleansClient(client => client.UseLocalhostClustering()).UseConsoleLifetime();
using IHost host = builder.Build();
await host.StartAsync();
IClusterClient client = host.Services.GetRequiredService<IClusterClient>();
IGreet receptionist = client.GetGrain<IGreet>();
string greetings = await receptionist.SimpleGreeting();
Console.WriteLine(greetings);
await host.StopAsync();
}
In this simple example, we are using the Interface as an identity that could be used to locate the grain. We leave you with a puzzle. The silo did not say anything about the grain. How could it resolve IGreet when the client calls it?
Before we leave; doesn’t the application feel the same pressure in the modern day of cloud computing to be available and ready to serve quickly like an actor with pressure from social media? (The Copy director was cringing when he read this stanza 😊)
Until next time, happy coding.