async-ring-adapter
async-ring-adapter copied to clipboard
An Aync Ring adapter, written on top of netty
Ring netty adapter
An netty adapter impl on top of netty for used with Ring
I write another one using pure java http-kit
Quick Start
me.shenfeng/async-ring-adapter "1.1-SNAPSHOT"
(use 'ring.adapter.netty)
(defn app
[req]
{:status 200
:headers {"Content-Type" "text/html"}
:body "hello word"})
(run-netty app {:port 8080
:netty {"reuseAddress" true}})
netty options
- connectTimeoutMillis
- keepAlive
- reuseAddress
- tcpNoDelay
- receiveBufferSize
- sendBufferSize
- trafficClass
- writeBufferHighWaterMark
- writeBufferLowWaterMark
- writeSpinCount
see netty doc
why
-
Netty is well designed and documented. It's fun reading it's code. It's high performance.
-
Netty's HTTP support is very different from the existing HTTP libraries. It gives you complete control over how HTTP messages are exchanged in a low level. Because it is basically the combination of HTTP codec and HTTP message classes, there is no restriction such as enforced thread model. That is, you can write your own HTTP client or server that works exactly the way you want. You have full control over thread model, connection life cycle, chunked encoding, and as much as what HTTP specification allows you to do.
Limitation
- Serving file is not optimized due to it's better be done by Nginx, so as compression.
Async extension
You write a ring handler this way
(defn handler [req]
{:status 200 :headers {} :body "hello world"}) # accept a Clojure map, return a map
defasync just like defn. The difference is: compute the respone map (possiblity asynchronous, in an other thread), give it to cb, cb can be passed around.
interface design suggestion welcome
Currently, http-kit use the same defasync mechanism, So you should have No trouble switch between them two.
example
(:use ring.adapter.netty)
(defasync async [req] cb
(.start (Thread. (fn []
(Thread/sleep 1000)
;; return a ring spec response => {:status :headers :body}
;; or just :body
;; call (cb req) when response ready
(cb {:status 200 :body "hello async"})))))
;; or this way, just wrap with async-response
(defn async [req]
(async-response respond!
(future (respond! {:status 200 :body "hello async"}))))
(run-netty async {:port 8080})
Benchmark
There is a script ./scripts/start_server will start netty at port
3333, jetty at port 4444, here is a result on my machine
how to run
# start jetty, use ab to benchmark it; do it with netty the same
lein deps && lein javac && ./scripts/bench
ab -n 300000 -c 50 http://localhost:4444/ #11264.90 [#/sec] (mean)
ab -n 300000 -c 50 http://localhost:3333/ #12638.37 [#/sec] (mean)
Contributors
This repo was fork from datskos