Websockets with Clojure

Kevin Greene

 4 min read

As we continue to evaluate Clojure, new avenues present themselves. In the past, highly concurrent processing at Spantree has been done with node.js or a JVM solution on top of Jetty. While these work, I never found them particularly easy or enjoyable to use.

Enter Clojure.

Recently I worked with some colleagues on an app designed around spectating runners. To quickly create an MVP, we needed a server that would broadcast coordinates periodically to all users who cared. Websockets seemed like the way to go, and because various members on the team had mixed experiences with socket.io, we went with http-kit, the Clojure solution for websockets.

The actual definition of the server is very easy to setup:

loading

After this, all logic lives in the process-message function.

For initial messages, we need to create a map of ids to channels we need to broadcast on.

Because following is bidirectional in nature, we add the channel we just created to the list of channels listening to that ID.

loading

Each time we receive a message after the initial request, we simply broadcast whatever we receive to the channels registered as listening to the specific ID.

loading

Combine all of the previous code snippets, and the result is the MVP for a server that facilitates realtime bidirectional communication between several clients over websockets.

This is by no means the professional, final solution. It:

  • Has no authentication
  • Relies purely on user input to maintain the ID
  • Doesn't clean up when users disconnect

That said, this is still a working solution to our problem, and let us get where we needed to be in as much time as it has taken me to type up this blog post. In addition to demonstrating Clojure is a viable solution for websockets, it also demonstrated that Clojure is a viable solution for quickly prototyping an application.

Feel free to test the above application with the following code, which utilizes gniazdo, a Clojure websocket client to generate and test several user-ids with several longitude / latitude combinations.

loading