Akka Remoting

In this post I’ll be covering pretty much the same as the Akka.net Remoting page. So I would definitely suggest you read that instead or in conjunction with this post.

As Akka.net has been designed for distributed systems and because (as you’ll have seen from my previous post on Akka.net) you interact with Actor objects via messages. Distributing your Actors should be pretty simple and painless. Let’s see if that holds true.

Initially we’re going to simply create two console applications. Let’s start off by thinking of one as the AkkaServer and the other the AkkaClient (although conceptually, in many ways, the idea of a server and client are meaningless in such an application as they’re really just “peers”).

Let’s write some code

  • Both projects are going to be compiled in .NET 4.6, so go ahead a create two console applications, name the first AkkaServer and the second AkkaClient.
  • Next up, add the Nuget Packages for Akka and Akka.Remote to both projects.
  • We could now create a third solution for our shared types, but let’s just add a new project to the AkkaServer, mine’s named Shared, you’ll need to add the Akka Nuget package to this project also.
  • In the Shared project, add the GreetingActor (as outlined previously and in the Akka.net documentation, here it is for completeness
    public class Greet
    {
       public Greet(string who)
       {
          Who = who;
       }
    
       public string Who { get; private set; }
    }
    
    public class GreetingActor : ReceiveActor
    {
       public GreetingActor()
       {
          Receive<Greet>(greet =>
             Console.WriteLine("{0} Greeting {1}",
             Thread.CurrentThread.ManagedThreadId, 
             greet.Who));
       }
    }
    
  • Once built, add the Shared.dll as a reference to your AkkaClient, so you’ve got access to the same type of GreetingActor etc.
  • In the AkkaServer Main method simply place the following
    var config = ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
    
        remote {
            helios.tcp {
                port = 8080
                hostname = localhost
            }
        }
    }");
    
    using (var system = ActorSystem.Create("MyServer", config))
    {
       system.ActorOf<GreetingActor>("greeter");
       Console.ReadKey();
    }
    

    This code is taken from Remoting as is the next piece of code for the client

  • Now in the AkkaClient Main method place the following
    var config = ConfigurationFactory.ParseString(@"
    akka {
        actor {
            provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
        }
        remote {
            helios.tcp {
                port = 8090
                hostname = localhost
            }
        }
    }");
    
    using (var system = ActorSystem.Create("MyClient", config))
    {
       var greeter = system.ActorSelection(
          "akka.tcp://MyServer@localhost:8080/user/greeter");
    
       greeter.Tell(new Greet("Roger"));
    
       Console.ReadLine();
    }
    

Run the server and then the client and you should see (in the server console window) the Greeting Roger text.

What have we just done?

So as you can see, we’re using the ConfigurationFactory.ParseString to simply create our remoting configuration in both the client and server. For this example, both applications are expected to be available on the localhost and therefore require different ports to communicate through.

We then create our ActorSystem in each application, for the sake of this example, one is perceived as the server and one as the client, but the beauty of Akka.net is they can be deployed in a peer-to-peer manner (which we’ll look at also).

Our AkkaServer creates an instance of the GreetingActor and then waits for messages. The AkkaClient uses the ActorSelection method to locate the server Actor (or a known name greeter. Although ofcourse we could just find all Actors if we wished) and then via the Tell method sends a messages to the Actor running on the server.

Let’s move towards a Peer-to-Peer design

Time to create the classic peer-to-peer chat application. This is going to be very basic and built using the previous code. The only changes to the two solutions are in the Main methods. Keep the config code the same as it was, but in the server replace the existing code with

using (var system = ActorSystem.Create("MyServer", config))
{
   system.ActorOf<GreetingActor>("greeter");

   string msg;
   while (!String.IsNullOrEmpty(msg = Console.ReadLine()))
   {
      var greeter = system.ActorSelection(
          "akka.tcp://MyClient@localhost:8090/user/greeter");

      greeter.Tell(new Greet(msg));
   }
}

and in the client, the code is exactly the same except MyServer becomes MyClient and the akka.tcp line changes to akka.tcp://MyServer@localhost:8080/user/greeter. For completeness here’s the code in full anyway

using (var system = ActorSystem.Create("MyClient", config))
{
   system.ActorOf<GreetingActor>("greeter");

   string msg;
   while (!String.IsNullOrEmpty(msg = Console.ReadLine()))
   {
      var greeter = system.ActorSelection(
         "akka.tcp://MyServer@localhost:8080/user/greeter");

      greeter.Tell(new Greet(msg));
   }
}

If you run up both solutions, both will create their own greeter Actor and only upon receiving some input via Console.ReadLine, will try to connect to all greeter Actors on to other’s ActorSystem (i.e. server will try to send to client and vice versa).

All this is happening via TCP and hence we could just as easily move one of the applications onto another machine – as long as both are accessible to one another, they should seamlessly work.

So there you have it, a very basic introduction to peer to peer Akka.net objects.