Communicating errors in both directions
Hey team, I am trying to wrap the callbacks of a websocket connection with core.async. My idea is to have every socket connection have it's own core.async go-loop.
Here's a rough idea:
(defn add-socket! [socket]
(swap! sockets assoc (:id socket) socket))
(defn remove-socket! [socket-id]
(swap! sockets dissoc socket-id))
(defn undertow-config [{:keys [start-fn]}]
(let [socket-id (UUID/randomUUID)
receive-ch (a/chan)]
{:undertow/websocket
{:on-open
(fn [{transport :channel}]
(let [socket {:id socket-id
:transport transport
:receive-ch receive-ch}]
(start-fn socket)
(add-socket! socket)))
:on-message (fn [{:keys [message]}]
(a/>!! receive-ch (<-json message)))
:on-close-message (fn [{:keys [message]}]
(a/>!! receive-ch (ex-info "socket closed"
{:message message}))
(a/close! receive-ch)
(remove-socket! socket-id))
:on-error (fn [{:keys [error]}]
(a/>!! receive-ch error)
(a/close! receive-ch)
(remove-socket! socket-id))}}))
Here's how it could be used:
(defn connect-get [_req]
(socket/undertow-config {:start-fn (fn [{:keys [receive-ch]}]
(log/infof "starting socket!")
(a/go-loop []
(when-let [msg (a/<! receive-ch)]
(log/infof "got message: %s" msg)
(recur))))}))
Problem:
I currently handling the case, where if a websocket connection closes or there's some unknown error, the worker that takes from receive-ch can be notified and shutdown gracefully.
But, what about the other way around? What if my start-fn worker fails? I'd likely want this error to propagate up and close the websocket connection. What would be an idiomatic way to achieve this?For posterity: I think I was overthinking this. I can use an error-ch for the worker to report back.