ring-sse
ring-sse copied to clipboard
Prevent IllegalStateException on close
TL;DR: The committed code will not close the inner output-stream, write-body-to-stream will close that one for us and since it is a proxy that calls complete on the AsyncContext we did trigger it twice, provoking the IllegalStateException
Please accept my pull request. I noticed a minor problem where an IllegalStateException was thrown after sending asynchronous data and then closing the channel. Code like the example from the readme.
I 21-02-06 17:33:42,843 async-dispatch-8 g. wrserver.http.invoke :sse/on-client-disconnect {:status 200, :headers {Content-Type text/event-stream; charset=UTF-8, Connection close, Cache-Control no-cache}, :body #object[clojure.core.async.impl.channels.ManyToManyChannel 0x51df0104 clojure.core.async.impl.channels.ManyToManyChannel@51df0104]}
Exception in thread "async-thread-macro-1" java.lang.IllegalStateException: AsyncContext completed and/or Request lifecycle recycled
at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:52)
at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:72)
at ring.util.servlet$make_output_stream$fn__9013.invoke(servlet.clj:91)
at ring.util.servlet.proxy$java.io.FilterOutputStream$ff19274a.close(Unknown Source)
at ring.sse$eval18682$fn__18683$fn__18684.invoke(sse.clj:14)
at clojure.core.async$thread_call$fn__16270.invoke(async.clj:484)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
According to my analysis this might happen if complete
is called multiple times. complete
is called at the following point by ring: https://github.com/ring-clojure/ring/blob/1.9.0/ring-servlet/src/ring/util/servlet.clj#L129
It is called in a proxy method to the output stream. write-body-to-stream
will call close
on that stream for the user: https://github.com/ring-clojure/ring/blob/1.9.0/ring-core/src/ring/core/protocols.clj#L12
So when ring-sse
puts output-stream
inside of the with-open
block it will be "closed" twice and complete
will be called twice causing the Exception.
I did not get the exception with the following changes.