Akka Http is a module of Akka that provides a full HTTP and Websocket server and client implementation, building on the power of Akka Streams. This means backpressure and resilience transparently out of the box. Great!
I recently needed to implement a bi-directional Websocket channel where each connected client is handled by an actor. The examples I could find were mostly about building a chat and therefore with a broader focus. Here is my simpler example.
- Each Websocket connection gets assigned to an new actor
- This actor will reply with
"Hello " + s + "!"when receiving a String message
- This actor will pipe down to the client any Int value it receives.
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.
The key issue to solve was that I needed a reference to independently push messages down to the connected client. The trick
that helped me came from this post
by Bartek Kalinka. The idea is to pre-materialize a
Source.actorRef which jots down messages 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.
Every message sent to the
down actorRef above will be published as a
TextMessage from the source we just created.
The actor that brings this all together looks like this:
As it is born, it materializes the actorRef and the publisher Sink. When asked to return the handling flow, it creates
the flow using the
GraphDSL syntax and sends it back. In your route, it goes like
Now you can build your own custom logic and behaviour around the ClientHandlerActor. Full code is available on a GitHub repository. Note that this won’t work in a distributed setting. For that we’ll need a couple adjustments, in the next post!