Skip to content

eaba/AkkaNetFsmDemo

 
 

Repository files navigation

Akka.NET Finite State Machine Demo

This is an ASP.NET Core 3.1 demo project using Akka.NET to model a simple shopping cart that goes through 3 states:

  • Empty you can only add products in this state. Remove and confirm are not allowed here;
  • NonEmpty you can add products, remove existing products or confirm the cart;
  • Confirmed no more commands are acceptable in this state. The cart is effectively "frozen";

image-states.png

This behavior is modeled by the CartActor class. Take a look at that, first.

Getting started

Open this project with Visual Studio or Visual Studio Code and just hit F5 to run it. Data will be retained in the Data/app.db Sqlite database. If you want to start over, be sure to remove that file before restarting the application.

image-demo.gif

Command delivery

In this particular project, a user sends commands to the server by interacting with the UI that's defined in the wwwroot/index.html file.

The HTML interface references the MQTT.js JavaScript library to deliver commands to the MQTT server, that's been implemented in this very same application using MQTTnet. Take a look at the Startup class for its configuration.

Why MQTT and not ASP.NET Core SignalR, you ask? Well, because for this demo I needed to experiment with some extended features, such as QoS levels, retaining messages and the request/response pattern. SignalR is not providing any of that out of the box.

When a command is delivered via MQTT, the ApplicationMessageInterceptor will then relay it to the Akka.NET Actor System.

Domain events

When a command finally gets to the CartActor, it will:

  1. Validate the command (e.g. it ensures the product name is non-empty when you send an AddProduct command);
  2. Handle the command by creating a domain event such as ProductAdded and persisting that event to a durable storage (in this case a Sqlite database, that's considered the one and only "source of truth" for this project);
  3. Apply the domain event by mutating the cart state (e.g. it adds a CartLine to the CartState).

Recovering from faults

Should the CartActor stop working due to an unhandled exception or an application restart, the Akka.NET Actor System will respawn a new CartActor instance and make it re-apply all previous domain events in the same order they were persisted.

To "re-apply" here means to re-do only step 3 from the previous paragraph. In fact, there's no need to re-validate or re-handle commands, since we're not dealing with commands anymore. We're just dealing with those domain events that were persisted to the storage.

In this way, the CartActor will recover its previous cart state, as if nothing happened. We can say the CartActor is fault-tolerant.

Side effects

Whenever a domain event is persisted to the storage, a typical application will want handle that event and trigger one or more side effects (e.g send an email when the domain event CartConfirmed is persisted). Enacting side effects should be completely asynchronous and independent of the CartActor because they usually take long to complete and may even fail often when dealing with third party services or devices over the network.

This project ensures side effects are enacted asynchronously by querying the storage with the Akka.NET Persistence Query. You can see it being created in the ActorSystemAccessor class.

Warning note: this project provides just a demo implementation. Its only side effect is echoing domain events to clients. Usually, you'll want to track which events have been handled so they won't produce duplicated side effects (e.g. email being sent again when the application is restarted).

Client notifications

Whenever a domain event is persisted, it's also echoed to connected clients via MQTT as a side effect. You can see it happening in the Models/Actors/EventHandlers/NotificationActor.cs file.

TODOs

You'll find some //TODO comments scattered in the project. Those are notes for future updates that might come in this demo. Again, this is just a demo project so it cannot be used in production as it is.

About

Finite state machine demo with Akka.NET. Clients sends commands and receives notifications via MQTT.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 80.2%
  • HTML 19.8%