Deploying actors with Akka.NET


We have now ported both the code and configuration based deployment features of Akka.
This means that you can now use Akka.NET to deploy actors and routers on remote nodes either via code or configuration.

For those new to akka what does this mean?

Let’s say that we are building a simple local actor system.
It might have one actor that deals with user input and another actor that does some sort of work.

It could look something like this:

var system = ActorSystem.Create("mysystem");
var worker = system.ActorOf<WorkerActor>("worker");
var userInput = system.ActorOf<UserInput>("userInput");
while(true)
{
    var input = Console.ReadLine();
    userInput.Tell(input);
}

Ok, maybe a bit cheap on the user experience there, but lets keep the sample small..
Depending on input, the user input actor might pass messages to the worker and order it to perform some sort of work.

Now, lets say that it turns out that our worker can’t handle the load, since actors (act as if they) are single threaded, we might want to add additional workers.
Instead of letting the user input actor know how many workers we have, we can introduce the concept of “Routers”.

Router actors act as a facade on top of other actors, this means that the router can delegate incoming messages to a pool or group of underlying actors.

var system = ActorSystem.Create("mysystem");
var worker1 = system.ActorOf<Worker>("worker1");
var worker2 = system.ActorOf<Worker>("worker2");
var worker3 = system.ActorOf<Worker>("worker3");

var worker = system.ActorOf(Props.Empty.WithRouter(new RoundRobinGroup(new[] { worker1, worker2, worker3 })));

var userInput = system.ActorOf<UserInput>("userInput");
while(true)
{
    var input = Console.ReadLine();
    userInput.Tell(input);
}

Here we have introduced three worker actors and one “round robin group” router.
A round robin group router is a router that will use an array of workers and for each message it receives, it will delegate that message the one of the workers.

We do not need to change any of the other code, as long as the user input actor can find the worker router, we are good to go.

If we want to accomplish the same thing, but using a config instead, we can something like this:

 var config = ConfigurationFactory.ParseString(@"
	akka.actor.deployment {
            /worker {
                router = round-robin-pool
 # pool routers are not yet implemented
 # you have to use the group routers with an array of workers still
                nr-of-instances = 5
            }
");
var system = ActorSystem.Create("mysystem",config);
var worker = system.ActorOf<Worker>("worker");
var userInput = system.ActorOf<UserInput>("userInput");
while(true)
{
    var input = Console.ReadLine();
    userInput.Tell(input);
}

The worker router is no longer configured via code but rather ia a soft config, that could be placed in an external file if you want.
This means that we can scale up and utilize more CPU of our computer just by changing our configuration.
But what if this is still not enough?
We might need to scale out also, and introduce more machines.
This can be done using “remote deployment”, like this:

 var config = ConfigurationFactory.ParseString(@"
	akka.actor.deployment {
            /worker {
                router = round-robin-pool
                nr-of-instances = 5
                remote = akka.tcp://otherSystem@someMachine:8080
            }

    ....more config to set up Akka.Remote
");
var system = ActorSystem.Create("mysystem",config);
var worker = system.ActorOf<Worker>("worker");
var userInput = system.ActorOf<UserInput>("userInput");
while(true)
{
    var input = Console.ReadLine();
    userInput.Tell(input);
}

Using this configuration, we can now tell Akka.NET to deploy the worker router on a different machine.
The settings will be read from the config, packed on a remoting message and sent to the remote system that we want to create our
worker router on.
(This of course means that Akka.NET must run on the remote machine and listen to the port specified on the config)

So by just adding configuration, we can now scale up and out from a single machine to a remote server, or even a cloud provider e.g. Azure.

That’s all for now :)

For more info, see: https://github.com/rogeralsing/Pigeon

Introducing Akka.NET


akkanet

There are a lot of things going on right now.
First, Pigeon Framework now has a new name; Akka.NET.
We got OK from Typesafe to use the name since we are a pure port of real Akka.

We are also doing a lot of work on the core and remote libs.
We now have a real EndpointManager actor managing transports.
And we have and Endpoint actor for each active endpoint.
Thus, we now support multiple transports, even if only Tcp is provided out of the box right now.

There have been some progress on Routers too.
We now support “Group” routers, e.g. RoundRobinGroup and ConsistentHashingGroup.
“Pool” router support is currently being developed.

Another nice feature we have ported is remote deployment.
This is IMO maybe the coolest feature we have ported so far, this means that we can now via configuration decide if an actor should be deployed locally or remote.
If remote deployment is used, the local actor system will send a message to the remote system, telling it to create the given actor with all of its configuration on the remote node.

For more info see: https://github.com/rogeralsing/Pigeon

Massive improvements to Pigeon – Akka Actors for .NET


The last few weeks have been busy busy.
Me and Aaron have been making some massive improvements to Pigeon.
Most of the Akka features are now completed, remoting still needs some love and after that we will start porting Akka clustering.

One of the latest features we have added is logging.
We support the same features as real Akka, so logging can be done using the ActorSystem.EventStream, and there is also a BusLogging LoggingAdapter.

We are also leveraging the real Akka config, so we can enable logging based on the same configuration options that Akka has.
Here is a snapshot of the output from the StandardOutLogger when booting the ChatServer example:

2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Info [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Warning [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Error [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - StandardOutLogger started [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081 - now supervising akka.tcp://MyServer@localhost:8081/user [Thread 10]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081 - now supervising akka.tcp://MyServer@localhost:8081/system [Thread 10]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/system - now supervising akka.tcp://MyServer@localhost:8081/system/deadLetterListener [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka.tcp://MyServer@localhost:8081/system/deadLetterListener] to channel Pigeon.Event.DeadLetter [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/system - now supervising akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger [Thread 10]
2014-02-21 22:40:44 DebugLevel EventStream(MyServer) - Default Loggers started [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] to channel Pigeon.Event.Error [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Debug [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Info [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Warning [Thread 11]
2014-02-21 22:40:44 WarningLevel ActorSystem(MyServer) - {
  akka : {
    log-config-on-start : on
    stdout-loglevel : DEBUG
    loglevel : ERROR
    actor : {
      provider : "Pigeon.Remote.RemoteActorRefProvider, Pigeon.Remote"
      debug : {
        receive : on
        autoreceive : on
        lifecycle : on
        event-stream : on
        unhandled : on
      }
    }
    remote : {
      server : {
        host : localhost
        port : 8081
      }
    }
  }
} [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/user - now supervising akka.tcp://MyServer@localhost:8081/user/ChatServer [Thread 10]
2014-02-21 22:40:45 DebugLevel akka.tcp://MyServer@localhost:8081/user/ChatServer - received handled message ChatMessages.ConnectRequest [Thread 11]

Alot of the existing features have also been refined to conform even more to real Akka, e.g. ActorSelection have been rewritten to behave exactly like in Akka.
ActorRefs are now also serializable in messages, so you can send messages containing actorrefs across the wire and use them on remote systems.
The Akka RemoteDaemon is also coming along nicely, so we can create actors on remote nodes this way, the underlying deployment features are however not completed yet.

The Props class have also gotten new features, we can now configure dispatchers and mailboxes via the config and there is also a new dispatcher that lets you run actors in the main thread, to allow GUI updates in WPF/WinForms.

Well, there are alot of new features and bugfixes, so if you are interested in Actor Model Programming in .NET be sure to check out the Pigeon repository at https://github.com/rogeralsing/Pigeon

//Roger

 

Actor lifecycle management and routers – Akka Actors for .NET


Porting Akka to .NET

I finally got around to implement full lifecycle management in Pigeon.
The Pigeon actor behavior is now consistent with real Akka.

The following Scala test: https://github.com/akka/akka/blob/master/akka-actor-tests/src/test/scala/akka/actor/ActorLifeCycleSpec.scala
Is now ported to .NET and shows that the lifecycle events fire in the expected order: https://github.com/rogeralsing/Pigeon/blob/master/Pigeon.Tests/ActorLifeCycleSpec.cs

I’ve also managed to port the fundamentals of the Akka Routers, so RoundRobinGroup routing is now in place: https://github.com/rogeralsing/Pigeon/wiki/Routing

Completely boring blogpost but this is what I’ve been up to the last few days :-)

 

Configuring Pigeon – Akka Actors for .NET


When I began to write the configuration support for my Akka Actors port “Pigeon”, I used JSON for the config files.
I’ve now managed to get some nice progress porting Typesafe’s Configuration library too.
So Pigeon now uses HOCON notation for the config files, and thus, allows for re-use of real Akka config files in Pigeon.

This means you can write configurations like:

var config = ConfigurationFactory.ParseString(@"
# we use real Akka Hocon notation configs
akka {
    remote {
        #this is the host and port the ActorSystem will listen to for connections
        server {
            host : 127.0.0.1
            port : 8080
        }
    }
}
");
//consuming code
var port = config.GetInt("akka.remote.server.port");

This might sound overly optimistic, since Pigeon currently only utilize a handful of the properties from the config.
But still, it’s pretty much only substitution support and numeric units that is missing from the config lib now, so I hope to have a fully working config system in a few days.

Once that is done, I will start incorporating it in the ActorSystem and it’s sub modules.
For those who are interested, the configuration support can be reused in other kinds of applications.
You can read up on the HOCON spec from Typesafe here: https://github.com/typesafehub/config/blob/master/HOCON.md
My port to .NET can be found here: https://github.com/rogeralsing/Pigeon/tree/master/Pigeon/Configuration

If you are interested in using Actor Model programming for .NET, please check out Pigeon:
https://github.com/rogeralsing/Pigeon