The goal of my previous post was to handle each websocket connection
with an actor. This post goes on to achieve the same thing in a distributed setting.
As described in the Server Side Websocket Support
page of Akka Http, a Websocket connection is modelled as a Flow that ingests messages and returns messages.
In order to achieve a full bi-directional communication, where messages can independently be sent to the other end, the
handling actor needs a way to “enter” such flow without a request from the connected client. The trick (inspired by this post
by Bartek Kalinka) is to pre-materialize a Source.actorRef connected to a publisher Sink.
At this point, each message sent to the down actorRef will end up in the publisher Sink. We can then create a Source
out of this sink, and use that source as the output for the Websocket Flow required by Akka Http.
So far, same as previous post. The missing step is, how to connect this source originating on a remote node? This is what we want to achieve:
StreamRef to the rescue
The glorious Akka Streams library has
everything we need. An experimental feature lets us materialize a local Source into a StreamRef. You can think of that
as the equivalent of ActorRef for Streams; to name one, they both accomplish location transparency. We can then pass
the reference to the server and create there the handling Flow.
In this example, as the server receives an incoming Websocket connection, it asks its supervisor to provide a materialized source
for streaming down messages:
The supervisor forwards the request to one of the registered handling nodes - here chosen randomly:
The handling actor, running on a remote node does a few things:
Upon creation, registers with the listener node.
Creates a source of Strings and materialises it as a remote source.
Pushes a greeting down that source every time it receives a message.
Once the SourceRef has come back, the supervisor can create the needed flow:
Full code is available on a GitHub repository. Note that
this code is not meant for production - the StreamRef feature itself is marked as ‘may change’ at the moment of writing:
thread carefully! (Pun intended.)
If you have any suggestion, please don’t hesitate to leave a comment.