I'm programming a web application backend in Clojure, using among other things:
- http-kit as an HTTP server and client (nonblocking)
- monger as my DB driver (blocking)
- clj-aws-s3 as an S3 client (blocking)
I am aware of the performance benefits of event-driven, non-blocking stacks like the ones you find on NodeJS and the Play Framework (this question helped me), and how it yields a much better load capacity. For that reason, I'm considering making my backend asynchronous using core.async.
My question is : Can you recreate the performance benefits of non-blocking web stacks by using core.async on top of blocking client/driver libraries?
Elaborating:
What I'm currently doing are the usual synchronous calls :
(defn handle-my-request [req]
(let [data1 (db/findData1)
data2 (db/findData2)
data3 (s3/findData3)
result (make-something-of data1 data2 data3)]
(ring.util.response/response result))
)
What I plan to do is wrapping any call involving IO in a thread
block, and synchronize this inside a go
block,
(defn handle-my-request! [req resp-chan] ;; resp-chan is a core.async channel through which the response must be pushed
(go
(let [data1-ch (thread (db/findData1)) ;; spin of threads to fetch the data (involves IO)
data2-ch (thread (db/findData2))
data3-ch (thread (s3/findData3))
result (make-something-of (<! data1-ch) (<! data2-ch) (<! data3-ch))] ;; synchronize
(->> (ring.util.response/response result)
(>! resp-chan)) ;; send response
)))
Is there a point doing it that way?
I'm doing this because that's kind of the best practices I found, but their performance benefits are still a mystery to me. I thought the issue with synchronous stacks was that they use one thread per request. Now it seems they use more than one.
Thanks in advance for your help, have a beautiful day.