Skip to content

Instantly share code, notes, and snippets.

@nha
Created December 14, 2015 11:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nha/618fd914f60ccac94657 to your computer and use it in GitHub Desktop.
Save nha/618fd914f60ccac94657 to your computer and use it in GitHub Desktop.

Overview of Clojure web servers

I played with a lot of Clojure webservers (although I began to play with Clojure after Noir dissapeared). And I have not found yet a perfect match, and there are so many alternatives out there (probably too many).

So here is a quick reminder for me about those, but it could be useful to you too. Even better if it actually stirs a discussion and drives things in the direction I would like things to go.

Compojure

  • Pros (1):

    • easy, lots of templates/examples (ex. Luminous)
  • Cons (2):

    • Not performant (a thread per request), expect performances slightly better than rails
    • Not simple, the middleware model has inconvenients

Advice : None. Maybe add an asynchronous execution if it can be done transparently. I see it as an easy-to-get-started-with-but-then-move-away-from-it webserver.

Pedestal

  • Pros (3):

    • interceptor model, pleasant syntax to add interceptors to a subset of routes
    • performant router
    • supports json/transit/multipart forms transparently out of the box, without asking anything
  • Cons (4):

    • slow to reload if putting it in a component (I think you are supposed to use the reload interceptor)
    • no websocket support, manifold would be nice
    • no testing facility for async interceptors
    • requires buy-in (?)

Advice : I don't see anybody really caring about the servlet architecture. Or about the whole backend transformations (but maybe I just don't get it yet). I would focus on trying to be the reference webserver (ie. correct the cons above, and see suggestions at the end of the post)

Aleph

Pro (3):

  • Performant
  • backpressure
  • Websocket/SSE support when returning a manifold stream Cons (1):
  • Low level, do it yourself style (ie. it just gives you a way to make your handlers do something. No router, no nothing)

Advice : None. It is intended as a low-level solution, and looks good as-is. Not for everyone though.

Yada

Pro (3):

  • built on Aleph
  • content negociation
  • swagger integration
  • bidi is quite ok (something feels a bit odd though, but I cannot put my finger on it) Cons (2):
  • documentation (although not as bad as nginx-clojure)

Advice : documentation.

HttpKit

Pro (2):

  • Written in Clojure ! (and Java...)
  • performance looks good (see the 600K concurrent connections post) Cons (2):
  • No CORS support
  • Bugs ? Also, not a lot of recent commits

Advice : Looks like in maintenance mode. Clean that issue list (76), and those PR (8).

Nginx-Clojure

Note : I haven't played with it, mainly because of the lack of documentation. It looks interesting though.

Pros (2):

  • Nginx (performant, offload ssl, restart workers...)
  • Could this model allow zero-downtime updates ? That would be so awesome ! Cons (1):
  • Documentation. Also, I don't want to program in strings embedded in an nginx config file if that is the only way to do it.
  • Probably complicates a bit the first deployment

Advice : write docs, communicate.

Hoplon

Note : I don't know a lot about it. I just put it here so someone can comment. It looks like it is a simple Clojure{Script} alternative to Om. Easier, less performant, not necessarily simpler.

Pros :

  • easy Cons :
  • framework (?)

Immutant

Note : I haven't played with it.

Pros :

  • integrated (caching, messaging, scheduling, wildfly deploy) Cons :
  • no http client

Catacumba

Note : I haven't played with it, although the documentation looks excellent. I am probably going to try it next. There are example chat projects that look interesting, their heavy use of protocols put me off at first.

Pros (6):

  • documentation ! Like all funcool projects, the doc is very pleasant to read.
  • pedestal-like routing syntax
  • should be performant (on top of Ratpack)
  • backpressure
  • websockets, sse, cors, security, ssl...
  • unique features to dig : postal Cons (2):
  • Not completely sure about how pleasant the ct/routes syntax is, and about ditching the Ring spec (supposedly for the async story, but I thought the pedestal guys fixed that)
  • Not sure how one would integrate swagger etc.

Advice : you don't look like you need it :p

What did I do

I personally went from Compojure, put some of it production at work. Then tried to play with Aleph, moved to Pedestal for a personal project prototype. I then went to rewrite it as I was not completely happy. I am now rewriting it with Yada (and boot instead of leiningen), but again I am not completely happy. Read on.

Ideally

Ideally I would have (roughly by order of importance for me) :

  • pleasant syntax, asynchronous (Pedestal/Catacumba win)
  • handlers that can return core.async streams, deal transparently with SSE/Websockets/HTTP2 (Aleph/Yada/Catacumba win)
  • documentation, documentation, documentation (only Catacumba has a good story there, Compojure/Pedestal/Aleph/ are quite alright)
  • an easier security integration (I spent days making Compojure + Friend work in a way compatible with a pre-existing Node.js app), buddy looks promising though (same author as Catacumba)
  • an easy story to integrate swagger/liberator/whatever (request monitoring, hystrix, riemann ?). Not sure who wins there... Compojure ?

##################

Killer feature

##################

Yes, Clojure as a language is awesome. But we are still stuck deploying our apps like Java apps. Not too bad, far from ideal though.

Here is what I think would be a killer feature for Clojure apps:

  • persist HTTP/SSE/Websocket requests/connections across code reloads (ie. software updates).

It would basically give Clojure some of the Erlang/OTP/BEAM zero-downtime powers. Not exactly the whole "let it crash" thing, but the ability to have software updates that look like nothing happened. All the "chat-like" apps that use Websockets/SSE/HTTP2 as well as the traditional RESTy apps would greatly benefit from that (no error code between deploys !).

In my mind, that kind of feature could rally the Clojure community around around a single webserver. At least I know I would jump ships instantly. I am quite sure some folks also look at Erlang/Elixir not because of the language but because of the platform. We need a great single-server platform story !

What would be needed to get there ? Cooperation from the web server, the simplest thing I an think off would be a signal that would say : "Hold the existing websocket/SSE/HTTP/HTTP2 connections as well as the next incoming connections in memory/durable queue/whatever, don't feed them to the application code, let the current requests finish and let me know when they are all done". An optimizing step could be the ability to start a webserver in parallel of the one waiting to shut down, but not bind it to a port, and only then when it is ready ask the other to shut down nicely. I do think it is doable, given the right server architecture (ie. something like Nginx config reloads that seems possible because of a request queue shared between workers).

If you heard of something that does that, or have some idea about how it could be done, or just have a link to a webserver that has this kind of functionality, I would be really happy to hear about it !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment