A recurring core.async pattern

Midjourney prompt: Grabbing a virtual baton in a ray of light in sketch style in vibrant colors. Background is brimming with tech vibes, circuits and pulses.

I’ve found myself using Clojure core.async in a very specific way on several occasions, and I thought it might be worth sharing.

(require '[clojure.core.async :as async])

(def c
  (async/chan))

(async/go-loop []
  (when-let [msg (async/<! c)]
    (do-stuff msg)
    (recur)))

To test the code do-stuff could be replaced with println.

The cool thing about the above pattern is that the go-loop is automatically terminated when the channel c is closed.

As the complexity of do-stuff grows, it is more likely that it will throw an exception which will cause the go-loop to terminate. Extend the code with the following to avoid premature (silent) terminations:

(require '[clojure.core.async :as async])

(def c
  (async/chan))

(async/go-loop []
  (when-let [msg (async/<! c)]
    (try
      (do-stuff msg)
      (catch Exception e ; Consider if catching Throwable is needed
        ;; Replace println with favorite logging library
        (println (str "ERROR: " (ex-message e))))
    (recur)))

I’ve used the above pattern in combination with a WebSocket (Haslett) and a file system watcher (Beholder) among others.

core.async is very versatile.