Add docker-compose, README, fix SSE dispatch

Use Undertow dispatch for SSE handler to avoid Ring adapter conflict.
Add docker-compose.yml (port 4101 to coexist with local dev on 4100).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 20:48:54 +01:00
co-authored by Claude Opus 4.6
parent f64aa98b04
commit 6f20cd63c6
4 changed files with 79 additions and 6 deletions
+17 -6
View File
@@ -28,11 +28,8 @@
:prev_price (when prev-price (str prev-price))
:recorded_at (str recorded-at)}))
(defn- price-stream-handler [{:keys [binance]} req]
(let [^HttpServerExchange exchange (:server-exchange req)
price-atom (:latest-price binance)
headers (.getResponseHeaders exchange)
cors-origin (or (System/getenv "CORS_ORIGIN") "*")]
(defn- run-sse-loop! [^HttpServerExchange exchange price-atom cors-origin]
(let [headers (.getResponseHeaders exchange)]
(.setStatusCode exchange 200)
(.put headers (HttpString. "Content-Type") "text/event-stream")
(.put headers (HttpString. "Cache-Control") "no-cache")
@@ -59,7 +56,21 @@
(catch Exception _)
(finally
(remove-watch price-atom wkey)
(try (.close writer) (catch Exception _)))))
(try (.close writer) (catch Exception _))
(when-not (.isComplete exchange)
(.endExchange exchange)))))))
(defn- price-stream-handler [{:keys [binance]} req]
(let [^HttpServerExchange exchange (:server-exchange req)
price-atom (:latest-price binance)
cors-origin (or (System/getenv "CORS_ORIGIN") "*")]
;; Dispatch to a worker thread so the Ring adapter never processes
;; the return value — Undertow handles the exchange lifecycle directly.
(.dispatch exchange
(reify io.undertow.server.HttpHandler
(handleRequest [_ ex]
(run-sse-loop! ex price-atom cors-origin))))
;; Return nil; exchange is dispatched so adapter won't touch it.
nil))
(defn- latest-price-handler [{:keys [binance]} _req]