A F# Akka.NET actor example for pub-sub pattern with NATS server

Publish subscribe pattern

The publish subscribe pattern is definitely not a new software pattern but still very useful. Lots of people know the pattern as the Observer pattern from the GoF book. The basic idea is to avoid point to point coupling between a publisher of messages and subscribers of the message.

center

NATS

NATS is an open source lightweight messaging system build with high performance in minds. To learn more about design goals, supported features, and what NATS does NOT provide please consult the documentation.

This post is not meant as an introduction or tutorial about NATS so if you need to learn more about NATS I suggest that you visit the NATS website and watch Simple Solutions for Complex Problems by Tyler Treat and optionally Powered by NATS: Integration Patterns for Microservices Architectures by David Williams.

NATS is maybe not as well-known as Kafka or RabbitMQ so if you want to see a short comparison between Kafka, RabbitMQ, and NATS then I recommend this blog post.

There is an official C# client for NATS and you can see an example of the publish subscribe pattern in C# in the GitHub repository for the C# client.

This example was inspired by a recent MeetUp talk at the NATS Boulder group discussing how to combine Akka and NATS and also on how to use NATS to implement a lightweight version of Akka. Akka is a JVM based implementation of the Actor model in Erlang. On the .NET platform we have Akka.NET which also supports an F# API.

A NATS client can be in one of three states: disconnected, connected, or subscribed. This seems like a perfect fit for the Finite State Machine modelling one can do with Akka actors. The different states and transitions between states are:

center

Before we get started we need to install and run the NATS server. Luckily there is an official Docker image so installing the server is a simple as

docker pull nats

Starting the server is just as simple

docker run -d –name nats-main -p 4222:4222 nats

Please see the GitHub repositoy for the implementation of a F# Akka.NET actor used for the pub-sub pattern and lets turn to an example using the NatsActor:

let cf = new ConnectionFactory()

let system = System.create "system" <| Configuration.load ()
let subscriber1 = spawn system "subscriber1" (natsActor cf)

subscriber1 <! Connect
subscriber1 <! Subscribe "foo"

let subscriber2 = spawn system "subscriber2" (natsActor cf)

subscriber2 <! Connect
subscriber2 <! Subscribe "*"

let publisher = spawn system "publisher" (natsActor cf)

publisher <! Connect
publisher <! Publish ("foo", "Hello World!")
publisher <! Publish ("bar", "Hello Again!")

subscriber2 <! Disconnect
publisher <! Publish ("foo", "Goodbye!")

subscriber1 <! Disconnect
publisher <! Publish ("foo", "Goodbye Again!")
publisher <! Disconnect

Executing this code yields

Actor: subscriber2 received message: Hello World!

 Actor: subscriber1 received message: Hello World!

 Actor: subscriber2 received message: Hello Again!

 Actor: subscriber1 received message: Goodbye!

and you see that subscriber2 receives both messages whereas subscriber1 only receives the "Hello World!" message. Subscription tags can contain wildcards!

Notice that no one received the last message published. If no NATS clients subscribe to a subject then the message is lost.

Ideas for improvements

References

Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Addison-Wesley, 1994

Enterprise Integraton Patterns, Gregor Hophe and Bobby Woolf, Addison-Wesley, 2004

Reactive Design Patterns, Roland Kuhn and Jamie Allen, Manning Publications, 2016

Reactive Messaging Patterns with the Actor Model, Vaughn Vernon, Addison-Wesley, 2016


Please create issues at the Github repo Twitter.

Edit page on GitHub. Please help me to improve the blog by fixing mistakes on GitHub. This link will take you directly to this page in our GitHub repository.

There are more posts on the front page.

Creative Commons License
Content of this blog by Carsten Jørgensen is licensed under a Creative Commons Attribution 4.0 International License.