1

I am starting to look at Akka.Net framework with boot-camp.

I could understand the basic Actor concept and persistence using event sourcing.

I am stuck at understanding how a Domain Event will be dispatched and received by other actors.

Restricting to a single System locally deployed Actors and No DI containers and Using c# /ASP.NET API where I am separating each AgreegateRoot into its own project

I am conceptualizing something like

  • ManagerActor

    • -AggregateRoot
      • --ChildActor 1
      • --ChildActor 2
      • --ChildActor n
    • -ValidationActor

Manager Actor will receive command message and go through validation process and if validated will be sent to AggregateRoot Actor. Event will be generated inside root or child actors.

please advise on following:

To publish an event on something similar to eventbus from inside an Entity can I use the below syntax?

Context.System.EventStream.Publish(MyEvent);

To Subscribe to an event I understood that the syntax is

System.EventStream.Subscribe( subscriber,MyEvent)

I want the event published by an Actor to be handled by Handlers (other Actors), of which current AggregateRoot Actor or Child Entity inside should have no knowledge.

This is where I am totally stuck. How is this achieved?

subscriber in System.EventStream.Subscribe, is IActorRef. To get this I would need knowledge of the class.

should I create a startup bootstrapper which will reference all projects/ AggregateRoots and build Subscriptions to message Types there?

I have tried to find blogs or write-ups but did not have much luck.

Thanks in Advance.

TheMar
  • 1,934
  • 2
  • 30
  • 51

2 Answers2

2

Another solution to this is to use Akka.Cluster.Sharding which is perfect for this use case. However; I will admit cluster sharding is not a beginner topic. Cluster sharding allows you to setup how your actor will be created via props as well as a strategy for mapping messages to a specific "Entity".

Here's an example of the cluster sharding setup for an actor from the example in the blog post I have linked to above:

using(var system = ActorSystem.Create("cluster-system"))
{
    var sharding = ClusterSharding.Get(system);
    var shardRegion = sharding.Start(
        typeName: nameof(MyActor), 
        entityProps: Props.Create<MyActor>(), // the Props used to create entities
        settings: ClusterShardingSettings.Create(system),
        messageExtractor: new MessageExtractor(maxNumberOfNodes * 10)
    );

    // ... etc
}

And you could then send the message like this:

region.Tell(new ShardEnvelope("<entity-id>", new MyMessage()));

Message Extractor

The message extractor referred to above is a key component in making this all work. The message extractor allows you to map a message to a specific entity (actually entityId). So if your messages for example all have the Id of the target entity in them, then this becomes simple. Here is an example message extractor (once again from the petabridge blog post and Akka.Net code base):

public sealed class MessageExtractor : HashCodeMessageExtractor
{
    public MessageExtractor(int maxNumberOfShards) : base(maxNumberOfShards) { }
    public override string EntityId(object message) => 
        (message as ShardEnvelope)?.EntityId;
    public override object EntityMessage(object message) => 
        (message as ShardEnvelope)?.Payload;
}

public sealed class ShardEnvelope
{
    public readonly string EntityId;
    public readonly object Payload;

    public ShardEnvelope(string entityId, object payload)
    {
        EntityId = entityId;
        Payload = payload;
    }
}

I admit that this seems like a bit of overkill and I think this would be remedied if there was better first class support for virtual actors in Akka.Net.

Damian
  • 2,709
  • 2
  • 29
  • 40
  • Thanks. Looks more, in line with what I need. I have not even looked at Sharding. I will give it a try. I wonder how users trying to move from DDD to AKKA.net are evaluating/ working it out. – TheMar Jan 25 '17 at 15:42
1

I am separating each AgreegateRoot into its own project

I wouldn't have a separate project for each AggregateRoot, this seems like overkill to me. What do you gain by this? You can just use a class / actor, no need for an entirely separate project.

It sounds like you might be getting confused by how to reference the C# types that represent your events, which isn't surprising if you have a separate project per AggregateRoot - you'll quickly run into circular references. Try starting with a single project where you separate bounded contexts using folders. In each folder, create any aggregates you need, and any events they are responsible for. This way, all actors can see all the event types. Once this grows / becomes unmanageable you can look at splitting it out into separate projects, something along the lines of:

  • MyApp.BoundedContext1
  • MyApp.BoundedContext1.Events
  • MyApp.BoundedContext2
  • MyApp.BoundedContext2.Events

Note that the events your actors produce and subscribe to represent a kind of public contract / API throughout the system. Having them as separate DLLs as above avoids circular references (as the .Events project don't reference anything). So in this structure, MyApp.BoundedContext1 can have a reference to MyApp.BoundedContext1.Events and publish them. MyApp.BoundedContext2 can also reference MyApp.BoundedContext1.Events and subscribe to them.

I want the event published by an Actor to be handled by Handlers (other Actors), of which current AggregateRoot Actor or Child Entity inside should have no knowledge.

This is where I am totally stuck. How is this achieved?

Your publisher does not need knowledge of subscribers. The publisher just publishes a message to the EventStream. The context that both the actor and event type are defined in should be the same (i.e. publishers should 'own' their event types). For example, if you have a ValidationActor that publishes ThingValidated events, they should both be in the same context.

subscriber in System.EventStream.Subscribe, is IActorRef. To get this I would need knowledge of the class.

Which class? The subscriber already has knowledge of itself. You can just use Self to get the IActorRef. If you mean the event class, then see above about how to structure your project to reference this.

Once an actor is created, it can register for any event types it is interested in - you can put this code in the initialisation code of the actor itself if you need, or if you have singleton-style actors, in some sort of bootstrapper function if you prefer.

Community
  • 1
  • 1
tomliversidge
  • 2,339
  • 1
  • 15
  • 15
  • I get that "Once an actor is created, it can register for any event types it is interested in", but what if the Actor is not created. Lets say the Actor which needs to subscribe to event is handling the event to store the data to Read Database. I would not want to instantiate this Actor before it is required to handle the event. And if he actor is not instantiated Context. System.EventStream.Subscribe( self,MyEvent) will not be reached. -- Should I instatiate all Manager actors at Application start ? – TheMar Jan 14 '17 at 18:33
  • Why don't you want to instantiate it before it is required? How do you know when it will be required? why not just create it on startup? They use a tiny amount of memory if just sat around waiting for an event to happen – tomliversidge Jan 14 '17 at 18:38
  • tom, thanks may be as you said I was doing an overkill by thinking too much into remote deployments and shards. Thank you for sharing your knowledge. It will get me started on POC – TheMar Jan 14 '17 at 18:52
  • No problem. I've been trying to think of a scenario where you wouldn't want to start an actor on startup :) I guess if it does something expensive or uses a lot of ram etc? I guess in those sort of scenarios you could have a 'cheap' actor listen to an event, and this cheap actor could create the expensive one :) – tomliversidge Jan 14 '17 at 18:55
  • Tom, can you have a look at http://stackoverflow.com/questions/41781012/akka-net-and-in-memory-peristence I think you may know be able to answer it – TheMar Jan 23 '17 at 18:14
  • @TheMar Just had a look but sorry I haven't used Akka Persistence yet so don't know anything about it – tomliversidge Jan 23 '17 at 18:18