Hello, first of all, thank you for this library! I am considering using it
instead of the original adapter for a web project, but I ran into an issue with
an SSE handler. Here is a barebone handler that demonstrates the issue:
(Tested with Clojure 1.12.0-alpha5 and Java 21)
{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha5"}
;; info.sunng/ring-jetty9-adapter {:mvn/version "0.31.0"}
ring/ring-jetty-adapter {:mvn/version "1.11.0"}
}}
(ns sse-with-ring
(:require [clojure.java.io :as io]
;; [ring.adapter.jetty9 :refer [run-jetty]]
[ring.adapter.jetty :refer [run-jetty]]
[ring.core.protocols]))
(defn handler [_]
{:status 200
:body (reify
ring.core.protocols/StreamableResponseBody
(write-body-to-stream [_ _ output-stream]
(let [writer (io/writer output-stream)]
(future (loop [i 10]
(doto writer (.write (str "data: " i "\n")) .flush)
(if (zero? i)
(.close writer)
(do (Thread/sleep 100)
(recur (dec i)))))))))})
(def server (run-jetty (fn [req respond raise]
(try (respond (handler req))
(catch Exception e (raise e))))
{:port 12345
:async? true
:join? false}))
(comment (.stop server))
With ring/ring-jetty-adapter {:mvn/version "1.11.0"}, the endpoint behaves as
expected, streaming each line as soon as they are "produced":
curl -Nv localhost:12345
* Trying [::1]:12345...
* Connected to localhost (::1) port 12345
> GET / HTTP/1.1
> Host: localhost:12345
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 10 Jan 2024 16:14:34 GMT
< Transfer-Encoding: chunked
< Server: Jetty(11.0.18)
<
data: 10
data: 9
data: 8
data: 7
data: 6
data: 5
data: 4
data: 3
data: 2
data: 1
data: 0
* Connection #0 to host localhost left intact
But with info.sunng/ring-jetty9-adapter {:mvn/version "0.31.0"}, curl returns
immediately without displaying any of our "data: x" messages:
curl -Nv localhost:12345
* Trying [::1]:12345...
* Connected to lol (::1) port 12345
> GET / HTTP/1.1
> Host: lol:12345
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 10 Jan 2024 15:58:38 GMT
< Content-Length: 0
< Server: Jetty(11.0.18)
<
* Connection #0 to host lol left intact
I found out an issue explaining that it is perfectly valid for a ring
handler to return while the output-stream remains open, and it may be closed
later in another thread.
Note that this streaming handler only works in the original adapter with the
:async? true setting. Reading the spec, it is not evident to me why this is
the case, and it's a bit unfortunate as we have to wrap our otherwise completely
synchronous ring application with:
(fn [req respond raise]
(try (respond (handler req))
(catch Exception e (raise e))))
Maybe @weavejester could clarify why this is the case?
Hello, first of all, thank you for this library! I am considering using it
instead of the original adapter for a web project, but I ran into an issue with
an SSE handler. Here is a barebone handler that demonstrates the issue:
(Tested with Clojure 1.12.0-alpha5 and Java 21)
{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha5"} ;; info.sunng/ring-jetty9-adapter {:mvn/version "0.31.0"} ring/ring-jetty-adapter {:mvn/version "1.11.0"} }}With
ring/ring-jetty-adapter {:mvn/version "1.11.0"}, the endpoint behaves asexpected, streaming each line as soon as they are "produced":
But with
info.sunng/ring-jetty9-adapter {:mvn/version "0.31.0"}, curl returnsimmediately without displaying any of our "data: x" messages:
I found out an issue explaining that it is perfectly valid for a ring
handler to return while the output-stream remains open, and it may be closed
later in another thread.
Note that this streaming handler only works in the original adapter with the
:async? truesetting. Reading the spec, it is not evident to me why this isthe case, and it's a bit unfortunate as we have to wrap our otherwise completely
synchronous ring application with:
Maybe @weavejester could clarify why this is the case?