Also using SSE in a production pedestal web app 🙂
Not to pile on, but SSE is indeed very useful. It's the mechanism we use to stream data with Datastar. Now that Http-kit is supported in pedestal I might revisit making something compatible with the Clojure SDK we have. Why Http-kit you may ask? It handles client disconnections very well compared to Jetty.
Datastar is not something I was previously aware of. Looks interesting.
It is and Datastar v1 is coming soon! After brief look at pedestal's 0.8 source I think that our SDK may work out of the box. Am I right in thinking that if a response is an Http-kit AsyncChannel pedestal will leave it to the user to manage it? By that I mean sending data using the http-kit api directly, taking care of closing the channel?
Yes, Pedestal will pass a response with :body as an AsyncChannel though as-is. The WebSocket and SSE code builds on top of this.
Cool! I'd like to clarify just 1 thing if I may. From what I understand when the result of an interceptor is a core async channel, pedestal goes in "async mode". I was looking at https://github.com/pedestal/pedestal/blob/master/http-kit/src/io/pedestal/http/http_kit.clj#L43. Apparently this interceptor closes the http-kit channel we went https://github.com/pedestal/pedestal/blob/master/http-kit/src/io/pedestal/http/http_kit.clj#L89. It looks like the channel won't stay open after the interceptor chain is finished processing. What if one interceptor causes the execution to go async and the response is the http-kit channel? It would mean we want to send data beyond the lifetime of the interceptor chain but we couldn't. Am I missing something?
Let me check ...
Yes, as currently coded, we invoke http-kit/close on the async channel in this case. I think we should look at the response body, and only close the async channel if the response body is not, itself, the async channel. This latter case covers what you were saying about going async. I can update the sse tests to include one that goes async.
Nice! I think that would be the right behavior.
That is there are two cases: • Interceptor chain went async, but eventually provided a "standard" response body • Interceptor chain went async, but eventually provided an AsyncChannel response body In the first case we should close the AsyncChannel; in the second case we should not.
Yes in the first case the channel should definitely be closed
So do you think Datastar with Babashka is viable? Http-Kit is built-in, Pedestal should work with it (just not the servlet portions). I have a side project where I'm using Babashka as a server, and Svelte in the client, potentially it could be Datastar instead?
Short answer is yes. Now for the long answer. Currently datastar does it's thing by receiving SSE events. The v1 will extend this and will be more permissive. If you just need request response you will be able to return "text/html" the same way HTMX lets you. SSE will be when you want to stream updates to a page beyond the lifetime of a request. So if pedestal runs on babashka and pedestal can do SSE you can do all Datastar can do. We have a clojure SDK that get you one level higher than raw SSE. It's basically a formater for SSE events (and some goodies). I haven't tested it on babashka. I don't know if it means anything but one user has compiled it with graalvm.
This has always been the challenge in open source; it’s very hard to know your users if you are not signing contracts with them. I’d love this channel to not only be an avenue for support and news, but also just a discussion of apps built on top of Pedestal.
Thanks to a side-discussion w/ @jeremys I found some further issues with Http-Kit SSEs. Along the way, while testing, I found out that the response headers from the SSE code, were being lost. I had to add some coordination between a few bits of code to make it work properly. I've also tested both SSEs and WebSockets where the interceptors go async, they now work correctly. https://github.com/pedestal/pedestal/pull/921