# Clojure core.async to handle communication with rabbitmq

I'm learning how to use rabbitmq in the course of writing a webapp in Clojure that will need to call out to Python for occasional machine learning. On the Clojure side, the main library is Langohr, which for some reason doesn't make use of core.async.

For my ultimate use case, I expect the Clojure-side to only ever have to handle one message at a time, immediately on arrival. (The Python side, not shown, will be doing possibly time-consuming machine learning, and will occasionally just send back some weights to the Clojure-side, which will immediately be put to use.) So I don't expect to need any buffering or anything like that, and haven't put them in this proof-of-concept code. I also expect there to be only one producer and only one consumer for each channel.

Toy code connecting the two below, but here are some general questions first:

1. It seems sensible to me as a design choice to stick incoming and outgoing messages on a core-async channel, just because that's the standard choice, but is it over-engineering to do so when I could just use Langohr functions to listen and pass callbacks?

2. I'm using go loops and non-blocking puts and takes for everything except for the piece that actually waits to see if an external message is waiting on the channel and sends it out for processing; that one is a blocking take in a thread on the theory that everyone says that if something might sit for a while it should be a thread rather than a go-loop (though I confess to not quite understanding why). Is this wise?

With no further ado, some toy code that demonstrates the design. (Leaving off the namespace declaration, but, obvs, go, chan, go-loop, and thread plus all the angle bracket/bang functions come from core.async. )

 (defn say [outqueue async-channel message]
(go
(>! async-channel {:queue outqueue :content message})))

(defn dispatch-messages! [mq-channel async-channel]
(go-loop []
(let [{:keys [queue content]} (<! async-channel)]
(lb/publish mq-channel "" queue (json/write-str content) {:content-type "application/json"}))
(recur)))

(go
(>! async-channel message))))

(defn listen! [async-channel mq-channel queue]
(lc/subscribe mq-channel queue handler {:auto-ack true})))

(defn process-messages! [async-channel processor]
(loop []
(let [message (<!! async-channel)]
(processor message))
(recur))))

(defn setup-async-comm [mq-channel, inqueue, outqueue]
sender-async-chan (chan)
sender-func (partial say outqueue sender-async-chan)
(dispatch-messages! mq-channel sender-async-chan)
(lq/declare mq-channel inqueue {:exclusive false :auto-delete false})
(lq/declare mq-channel outqueue {:exclusive false :auto-delete false})