[HN Gopher] Server-sent events, WebSockets, and HTTP
       ___________________________________________________________________
        
       Server-sent events, WebSockets, and HTTP
        
       Author : grappler
       Score  : 273 points
       Date   : 2022-02-20 05:24 UTC (17 hours ago)
        
 (HTM) web link (www.mnot.net)
 (TXT) w3m dump (www.mnot.net)
        
       | rektide wrote:
       | No mention of what browsers do for notifications, Web Push
       | Protocl[1]. Which makes sense only in the context of the one of
       | the ancient grand-daddy issues of Fetch being completely ignored
       | by the powers that be[2], & the browser & the browser alone (not
       | the page) having the capability to hear & observe HTTP2+ PUSH
       | requests coming in. This github issue to let a fetch request hear
       | PUSH responses come back at it has been mostly ignored, for 3/4 a
       | decade.
       | 
       | Meanwhile Chrome is saying people don't use Push. Yeah, well,
       | because ye jerknuts have diluted & made unusable the best part of
       | it: the ability to be responsive to resources coming at us. What
       | a sad truckload of tragedy this undelivered capability has been.
       | To invent a new HTTP, HTTP2, with new capabilities, then spend
       | most of a decade ignoring & denying developers access to the best
       | parts of what you just invented. Irony & tragedy. Now they're
       | taking away PUSH[3], having never made it usable at all. Classic
       | frigging Google, what frigging fickle monsters, incapable of even
       | the most basic follow-through on what they start.
       | 
       | [1] https://datatracker.ietf.org/doc/html/rfc8030
       | 
       | [2] https://github.com/whatwg/fetch/issues/51
       | 
       | [3] https://groups.google.com/a/chromium.org/g/blink-
       | dev/c/K3rYL...
        
         | chrismorgan wrote:
         | I think you _may_ be misunderstanding the purpose of RFC 8030,
         | or if you do understand it (and after more careful
         | contemplation of your wording, I think you do) you're
         | conflating two different things. It's not something for web
         | pages to implement or use, but for user agents to implement,
         | providing a standard way of delivering events fielded via the
         | Push API (which _is_ for web content to use, and works well),
         | because browsers were all implementing their own stuff for
         | that, making interoperability or hosting your own push service
         | (which is on the public internet and receives events and then
         | sends them to the browser somehow) difficult.
         | 
         | This _happens_ to use HTTP /2 PUSH_PROMISE frames, and it's a
         | good use of them. _But that doesn't imply anything about
         | exposing HTTP /2 Server Push to arbitrary web content._
         | 
         | (I have no idea of the implementation status of RFC 8030,
         | whether any or all user agents have replaced their own _ad hoc_
         | systems with it.)
         | 
         | The fact of the matter is that HTTP/2 Server Push really just
         | didn't pan out for general web content: its original intended
         | purpose flopped, turning out to cause more trouble than it
         | solves; cache digests could make this _probably_ not so, but
         | they make it even more complex, and add a little overhead, so
         | that based on what's been seen so far, implementer consensus (
         | _consensus_ , not just Google) is that it's just not worth
         | trying. Sad but true. As for the remaining possible cases,
         | they're served about as well and more compatibly by older
         | techniques. (And compatibility is important: you emphatically
         | cannot depend on HTTP/2 working, so you mustn't _require_ HTTP
         | /2 features, so there's not a great deal of purpose in
         | implementing them at all.) So in the end, exposing HTTP/2
         | Server Push to client code is probably a net loss, significant
         | complexity spent for significant _risks_ , insignificant
         | uptake, and negligible concrete benefits. Google is bad, sure,
         | but I don't think this is an example of that.
        
           | rektide wrote:
           | > _As for the remaining possible cases, they're served about
           | as well and more compatibly by older techniques._
           | 
           | Noteably none of the alternatives deal directly in HTTP
           | resources. HTTP PUSH could have/should have allowed sending
           | new http resources directly. HTTP could have become a way to
           | allow a page to be reactive, as new content was streamed at
           | it, and this would have been a near ideal fit
           | architecturally, building on what the web is and what http
           | is, to meet with modern apps which have incoming new data
           | streamed to them all the time.
           | 
           | Instead we have this long list of un-HTTP non-resourceful
           | hacks, to have a separate eventing system. Because HTTP2
           | built the tech then failed to let the page use it. Technology
           | like RFC 8030 demonstrate what that better future look like &
           | is widely used, just, as you say, not by the page directly.
           | This is a fuck up, a huge missed opportunity. I disagree with
           | your assessment that backwards compatibility means we should
           | stick to the same ratty old non-resourceful options we've
           | been stuck with: we should & ought to use better. That good
           | tech was impossible to use directly by the page was a sin
           | that prevented this technology from receiving adoption &
           | attention.
           | 
           | It feels like everyone is fixated on the cache-digest
           | problem, which indeed is hard, but it's just not relevant.
           | There's so many other interesting & good architectural
           | options that this tech opened up. Just, the web never
           | empowered developers to use them.
        
       | dpweb wrote:
       | Been on SSE since about 10 years ago, and seems a nice time to
       | modernize and move to something that supports peer to peer
       | (browser) and not just client server. Anyone using anything like
       | that now?
        
       | tjpnz wrote:
       | When would you use WebSockets versus SSE? The introductory
       | example most tutorials on WS give is for chat, yet it looks like
       | you could implement the same functionality using a combination of
       | REST and SSE. That would allow you to stay in HTTP land which
       | seems desirable based on all of the issues I've read about people
       | having here.
        
         | toomim wrote:
         | Your question is the topic of the article [1] Mnot was replying
         | to.
         | 
         | [1] https://news.ycombinator.com/item?id=30312897
        
         | samwillis wrote:
         | SSE are single direction (server to client), you could use a
         | http get/post for message from the client but then if you have
         | multiple servers it could land of another server. Websockes
         | allow you to have the server end processed in one place.
         | 
         | The big advantage of SSE when doing a simple event stream from
         | the server is that they can be implemented in stacks that don't
         | support Websockes, such as many of the older Python frameworks
         | (i.e. Django) built on top is WSGI. To use Websockes with these
         | frameworks they either need upgrading to ASGI (or equivalent)
         | or you have to run an additional server process for Websockes.
         | 
         | I do a lot of Django, SSE are super easy with it, just a
         | StreamingResponce implementing the SSE protocol. I have then
         | tended to use Gevent with Gunicorn to handle the long streaming
         | responses rather than the default threaded workers.
         | 
         | There are few caveats around implementing a heartbeat event and
         | ensuring they are closed properly when the client disconnects.
         | This can be super annoying, I tent to kill the connection every
         | couple of minutes as you don't always know when the client has
         | disconnected. Also buffering in reverse proxy's need to be
         | worked around.
         | 
         | To be honest though as Django gains better support for
         | Websockes I would probably use them over SSE even for a single
         | direction event stream, less edge cases to think about.
        
           | infamia wrote:
           | Just curious, is there anything wrong or missing from
           | Django's current websockets support? Django has supported
           | websockets via ASGI and Channels since 3.0 (about two years
           | ago)? I'm working on a Django project that will require
           | updating clients async.
        
             | samwillis wrote:
             | Nothing particularly now, however if you are working on an
             | older stack that hasn't migrated to ASGI it's just not
             | particularly easy.
             | 
             | For long running responses like websockets and SSE you
             | really need to use none threaded worker processes (one
             | websocket connection would clog up a a single worker
             | thread). Until recently the best way to do this was with
             | Gevent with Gunicorn. The asyncio stuff that is coming to
             | Django is a great addition, they have just merged async
             | querysets. However it's not the full framework yet and so
             | although views and querysets are async, the db adapters are
             | not yet and use a thread pool internally. I'm hoping they
             | get to that level of the framework soon, it's been a
             | sessions undertaking to asyncify the Django api.
             | 
             | I like the idea of continuing to use the original sync api
             | everywhere except on websocket/SSE views or views with _a
             | lot_ of io (many db query's and http api calls) where it
             | has a proper advantage.
             | 
             | I haven't looked in detail recently but I would still
             | consider whether going Gevent/Gunicorn (which is basically
             | magic) is better than asyncio at the moment for Django. May
             | be worth doing some benchmarking.
             | 
             | I kind of wish Gevent had won the battle with Asyncio.
        
           | [deleted]
        
           | merb wrote:
           | btw. sse also works good with http/2
        
         | yencabulator wrote:
         | One thing that comes to bite you surprisingly quickly is that
         | with SSE+POST, you lose ordering in the C->S direction.
         | Consider a chat client that POSTs every line you type; two
         | POSTs might get reordered in-flight while two WebSocket
         | messages won't.
        
         | austincheney wrote:
         | Websockets are bidirectional, which means a slimmer alternative
         | to XHR from the browser. Think of websockets as a TCP pipe
         | without additional overhead. The limitation of websockets is
         | that it is a single socket and data cannot be interlaced, which
         | means it must be queued per direction.
        
       | stavros wrote:
       | I'm just now planning to make a web app with a Django backend
       | that will need simple notifications on the frontend, and I'd like
       | to keep the frontend as light as possible (no React, for
       | example).
       | 
       | What would you recommend? Websockets? MQTT?
        
         | musingsole wrote:
         | WebSockets
         | 
         | Frameworks like JustPy have used it to couple the frontend to
         | the backend and have a Python server doing all the logic work
         | (i.e. frontend just passes everything over WebSockets to the
         | server and asked what to do). It's an awesome demonstration of
         | what WebSockets can do.
         | 
         | MQTT has no place on the web. It barely has a place in IoT and
         | should lose all rights to that claim yesterday.
        
           | Xunjin wrote:
           | I'm sorry but you seem to really hate MQTT, could you expand
           | that?! I've been using it through Google IoTCore and has been
           | pretty good.
        
           | stavros wrote:
           | JustPy sounds interesting, thanks. Why the MQTT hate, though?
        
       | olesku wrote:
       | I've been working on a pub/sub server that supports both
       | Websockets and SSE as a hobby project for a couple of years. It
       | have been successfully implemented and is used in production on
       | some high traffic sites with 300k+ simultaneous connections. If
       | someone are interested the projects webpage can be found here:
       | https://github.com/olesku/eventhub
        
       | mmzeeman wrote:
       | The best way to do pub/sub on the web with a standard protocol is
       | MQTT (https://mqtt.org). It supports websockets, it scales,
       | supports authentication, can handle unreliable networks.
       | 
       | We use it exclusively for the soon to be released 1.0 version of
       | Zotonic. See: https://test.zotonic.com (running on a 4.99 euro
       | Hetzner vps).
       | 
       | We developed an independent support javascript library called
       | Cotonic (https://cotonic.org) to handle pub/sub via MQTT. This
       | library can also connect to other compliant MQTT brokers. Because
       | MQTT is fairly simple protocol, it is fairly easy to integrate in
       | existing frameworks. Here is an example chat application
       | (https://cotonic.org/examples/chat) which uses the open Eclipse
       | broker.
        
         | musingsole wrote:
         | > The best way to do pub/sub on the web with a standard
         | protocol is MQTT
         | 
         | Strong disagree. MQTT has no place in a world with WebSockets.
         | MQTT knowledge is so esoteric in comparison. Maybe it's the
         | Haskell of transport protocols: really friggin smart, but not
         | if you're trying to be useful to society at large.
        
           | detaro wrote:
           | MQTT is neither "esoteric" or "not useful to society at
           | large" nor is WebSockets vs MQTT even a useful contrast,
           | since WebSockets to a large degree addresses a different
           | level of the stack (and indeed "MQTT over WebSockets" is a
           | common way of deploying it).
        
           | mmzeeman wrote:
           | MQTT is a proven protocol. It's design started started more
           | than 20 years ago. The protocol was designed to be easy to
           | implement. It is simple to implement if you want. There are
           | multiple brokers, and client libraries available. So why
           | invent a new protocol, when an open, standardised protocol
           | already exists.
           | 
           | Open pages in a browser are not that different from IoT
           | devices.
        
             | musingsole wrote:
             | > So why invent a new protocol, when an open, standardised
             | protocol already exists.
             | 
             | Because despite being a dinosaur, it still only has
             | middling adoption. It exists in a particular niche of a
             | particular niche of computing.
             | 
             | HTTP, in contrast, is English to MQTT's German. One is just
             | infinitely more common and accessible to the majority of
             | the world. So, if you're serious, use it.
        
         | ShoveItHN wrote:
         | Look at your first two sentences. You say MQTT supports
         | authentication like MQTT.
        
       | jkarneges wrote:
       | > The question, then, is how we enable intermediation for pub/sub
       | 
       | My company (Fanout) is attempting to solve this via the Generic
       | Realtime Intermediary Protocol:
       | https://pushpin.org/docs/protocols/grip/
       | 
       | The idea is to enable origin servers to delegate connection
       | management to a proxy tier, without introducing a new client-
       | facing protocol.
        
       | the_gipsy wrote:
       | Can Web Push Notifications not also be considered as an
       | alternative?
       | 
       | They are quite different from SSE and WebSockets in some aspects.
       | Using Web Workers for some core feature shouldn't be considered
       | lightly. But the end result is pub/sub, so it's worth to check
       | out.
       | 
       | https://developer.mozilla.org/en-US/docs/Web/API/Push_API/Be...
        
         | karl42 wrote:
         | Technically it would fit nicely. Unfortunately, it requires the
         | user to explicitly give permissions to show notifications to
         | the website, even if you don't show any notifications. This is
         | a blocker for its usage in many cases.
        
           | mmis1000 wrote:
           | I think you probably mean web Notification. Although it is
           | always use with Web Push. And also it is generally rate-
           | limited due to its default usage (display a message to user).
           | On the other side, Websocket and SSE talks to program, there
           | is just no rate limit thing exist.
        
       | aww_dang wrote:
       | Jetty/Cometd abstracts away the problems mentioned in the
       | comments here. I enjoyed it for personal projects without the
       | enterprisey overhead. It does integrate with that stuff if you're
       | into that.
       | 
       | Just my personal preference. Not claiming anything beyond that.
        
       | eldelshell wrote:
       | My experience with SSE so far (take this as recommendations if
       | you wish)
       | 
       | You need to implement a server-side heartbeat feature.
       | 
       | You need to handle the close event from EventSource and be able
       | to reconnect.
       | 
       | Tabs can be problematic. When you subscribe, you use a URL with a
       | nominal ID to identify the client. For example, on a chat app,
       | you would use /api/sse/userA/subscribe
       | 
       | Problem is, if userA starts opening tabs, each tab creates a new
       | subscription for userA so you need to randomize each connection
       | (userA-UUID).
       | 
       | If you don't use a nominal id, the server won't know to which
       | subscriber to send the data and you don't want to broadcast all
       | your chats.
       | 
       | I've used the Broadcast channel API in conjunction with SSE to
       | have only one tab handle the SSE connection, and broadcast
       | incoming SSEs to the other tabs which also reduces the number of
       | connections to the server to one.
       | 
       | On the server it's also a PITA because not all instances/pods
       | have the subscribers list. The way I've found to solve this is
       | with clustering the instances with Hazelcast or Redis or a MQ.
       | 
       | But once you figure out all this, SSE works quite well.
        
         | remram wrote:
         | I thought it reconnected automatically, and sent the last
         | received event ID? Why do you need heartbeat?
         | 
         | Why don't you want to send the event to all the tabs? Why do
         | you want to differentiate the tabs (by UUID)?
        
           | parkerduckworth wrote:
           | Yeah my personal experience is that if a SSE server has
           | clients subscribed, and it goes down, the clients reconnect
           | automatically once the server starts back up.
           | 
           | Only thing is the message ids reset when this happens.
        
         | qwtel wrote:
         | Sounds like a service worker, for which there's only one active
         | at a time for all tabs (and can communicate with them) could
         | help with your client side issues.
        
           | greeklish wrote:
           | Here's an article on how to multiplex websockets [1]
           | 
           | It looks pretty clever, I wish more websocket frameworks like
           | [2] supported this out of the box (with failovers for
           | safari).
           | 
           | [1] https://dev.to/ayushgp/scaling-websocket-connections-
           | using-s... [2] https://www.npmjs.com/package/hydrated-ws
        
             | taf2 wrote:
             | This works great just not for safari since for some reason
             | the WebKit team felt in 2015 it made since to remove
             | SharedWorkers
             | 
             | https://stackoverflow.com/questions/28310501/why-did-
             | safari-...
        
         | dpweb wrote:
         | These are all potential issues with plain sse, but are pretty
         | easily solved in a few lines of code.
         | 
         | Granted the benefits of sse: no additional port to open, no
         | dependencies - just slip your logic into your routing at
         | /events. Of course this may not be important for some.
         | Websockets are a good choice as well. I tend to id clients on
         | ip address not connections however, depends on the specific
         | app.
        
         | sbergjohansen wrote:
         | Also, when using an nginx reverse proxy, including 'X-Accel-
         | Buffering: no' in the HTTP header of the server response may be
         | required to keep events from being buffered.
        
         | samwillis wrote:
         | This chimes a lot with my experience. Although I think SSEs are
         | brilliant if the stack I'm using supports Websockets I would
         | probably default to them even for a simple event stream now.
         | 
         | To add to your list of problems, I have had memory leaks with
         | SSE responses stuck open on the server even when the client
         | disconnects. Resorted to killing the response on the server
         | every couple of minutes and relying on the client reconnecting.
        
         | taf2 wrote:
         | SharedWorker is a good solution for handling the multiple tab
         | issue
        
       | dSebastien wrote:
       | I'd love to see support for pub/sub as part of HTTP.
        
         | cryptica wrote:
         | I don't understand this mindset. HTTP was a protocol designed
         | for transferring text files. It literally means 'HyperText
         | Transfer Protocol'. Its use case has been getting broader and
         | broader over time. Why does everyone want it to be a silver
         | bullet? There are no silver bullets. Jack of all trades, master
         | of none. WebSockets is great because it's a separate protocol
         | and can be dealt independently by browser and server vendors as
         | security and functional requirement change.
         | 
         | HTTP was never designed for pub/sub... How does the additional
         | layer of complexity provided by HTTP for file transfers (e.g.
         | request headers with each request, response headers, cookies
         | sent in each request, mime types, etc...) benefit us for the
         | pub/sub use case? It just adds overhead and makes it harder for
         | vendors to fully implement HTTP. What used to be a simple
         | protocol is becoming prohibitively complicated.
        
           | pbowyer wrote:
           | > Why does everyone want it to be a silver bullet?
           | 
           | I agree with this sentiment. But mnot spells out well in his
           | article why adding it to HTTP would be pragmatic (CDNs,
           | standardised, caching)
        
       | tomberek wrote:
       | SSE has been extremely useful for my purposes. And the issues
       | with scaling it are similar in nature to scaling and getting a
       | similar feature set out of any solution. But in terms of speed to
       | PoC/MVP nothing has been as easy as SSE. The final reasoning is
       | that it can easily be inspected, debugged, curl'd, and so forth.
       | 
       | Not sure how often this is done, but I've been sending query
       | parameters along with the request and using it to stream results
       | back to the client for low-latency initial responses to long-
       | running API calls.
        
       | [deleted]
        
       | nesarkvechnep wrote:
       | Off-topic but I would like to share with all of you a proposal
       | from Mark Nottingham on HTTP cache channels[1]. Sadly it went
       | nowhere but in my opinion was and still is very promising idea.
       | 
       | [1] https://datatracker.ietf.org/doc/html/draft-nottingham-
       | http-...
        
       | EGreg wrote:
        
         | djrobstep wrote:
         | I wish the moderators would ban this incredibly annoying comic,
         | which gets posted any time anybody posts anything that might
         | improve any situation, even if it's not standardization-
         | related.
        
           | EGreg wrote:
           | That's kind of how HN is - snarky and dismissive. At least I
           | did it summarizing the actual post. I support actual attempts
           | at improvements. And I don't eee much issue with websockets
           | implementations.
           | 
           | I myself have posted links to stuff I worked hard on for
           | years ... not just proposing but implementing and testing for
           | years ... and it just gets silently downvoted with an
           | occasional comment about how YouTube sucks or something
        
             | mattsahr wrote:
             | Downvoted. Youtube sucks.
        
         | treve wrote:
         | I knew what this was going to be before I clicked it. This gets
         | posted way too often any time a new thing is proposed. If the
         | sentiment were universally true, we'd get very few new
         | standards.
         | 
         | New ideas get proposed all the time, many of them fail and some
         | are successful. We are better off for that. Don't discourage
         | people from participating in the marketplace of new ideas. It's
         | snarky and not constructive.
        
           | EGreg wrote:
           | Actually I was summarizing his article. The situation he
           | describes in pubsub for Websockets is exactly this.
        
             | treve wrote:
             | The way you wrote this sounds like you disagree with my
             | sentiment because I misunderstood your original intent with
             | linking the xkcd, but I understood that you felt that the
             | comic was an apt description.
        
             | josephg wrote:
             | Thats not a summary, any more than "action movie" is a
             | summary of Iron Man.
             | 
             | That comic cleverly names a common technical motivation.
             | But it doesn't summarize the work because it removes all
             | the interesting & relevant technical details.
             | 
             | Its also really done at this point. That link has been
             | posted 733 times in HN comments[1]. It was funny the first
             | time, but its time to let it die.
             | 
             | [1] https://hn.algolia.com/?dateRange=all&page=0&prefix=tru
             | e&que...
        
         | leg100 wrote:
         | God this is tiresome. There are so many good xkcd comic strips
         | that could be posted with more nuance and applicability to the
         | subject matter. But almost everytime a link to xkcd is posted,
         | it is to #927.
         | 
         | It's utterly inane. Anyone who frequents HN will have seen it
         | linked before and will know not to bother to link to it again.
         | So why do it?
        
       | josephg wrote:
       | In case people don't know, Mark Nottingham (the author) is the
       | chair of the HTTP working group at the IETF. He isn't just some
       | guy with opinions on the internet. (Sorry mnot!)
       | 
       | I've never found pub/sub quite the right abstraction, because
       | almost every implementation I've seen has race conditions or
       | issues on reconnect. Usually its possible to lose messages during
       | reconnection, and there's often other issues too. I usually want
       | an event queue abstraction, not pub/sub.
       | 
       | I met mnot a few years ago when we (the braid group) took a stab
       | at writing a spec for HTTP based streaming updates[1]. Our
       | proposal is to do state syncronization around a shared objects
       | (the URL). Each event on the channel is (explicitly or
       | implicitly) an update for some resource. So:
       | 
       | - The document (resource) has a version header (ETag?).
       | 
       | - Each event sent on the stream is a patch which changes the
       | version from X to Y. Patches can either be incremental ("insert A
       | at position 5") or if its small, just contain a new copy of the
       | document.
       | 
       | - You can reconnect at any time, and specify a known version of
       | the document. The server can bring you up to date by sending the
       | patches you missed. If the server doesn't store historical
       | changes, it should be able to just send you a fresh copy of the
       | document. After that, the subscription should drip feed events as
       | they come in.
       | 
       | One nice thing about this is that CDNs can do highly efficient
       | fan-out of changes. A cache could also use braid to subscribe to
       | resources which change a lot on the origin server, in order to
       | keep the cached values hot.
       | 
       | [1] https://datatracker.ietf.org/doc/html/draft-toomim-
       | httpbis-b...
       | 
       | We've done some revisions since then but have been working on
       | getting more running code before pushing forward more with the
       | approach. Most recent draft & issues: https://github.com/braid-
       | org/braid-spec/blob/master/draft-to...
        
         | toomim wrote:
         | These are great insights by both Mnot and Josephg. I've
         | followed up on this conversation on the HTTP working group
         | mailing list:
         | 
         | https://lists.w3.org/Archives/Public/ietf-http-wg/2022JanMar...
        
         | samwillis wrote:
         | Did you consider using CRDTs for your document sync? It sounds
         | like what you were implementing was somewhere between OTs and
         | CRDTs and trying to create a standard event protocol for them?
         | 
         | CRDTs remove the need keeping track of all (or any just recent)
         | revisions on the server as you would with OTs, your server can
         | be stateless and just act as a message broker between clients.
         | 
         | Edit:
         | 
         | Should have followed your links, yes that's exactly what you
         | are doing.
         | 
         | https://braid.org/
        
         | jamil7 wrote:
         | Thanks a lot for sharing this, it's very relevant to my work at
         | the moment.
        
         | thibauts wrote:
         | Here is an event stream abstraction that has very strong
         | semantics (exactly once in most cases) with simple usage
         | examples, native HTTP and websockets APIs, strong atomicity and
         | durability guarantees [1].
         | 
         | What it doesn't have is clustering and a father that's != null
         | at marketing =]
         | 
         | [1] https://github.com/thibauts/styx
        
         | mathgladiator wrote:
         | pub/sub is a horrible abstraction. I've written about it here:
         | http://www.adama-lang.org/blog/pubsub-sucks
         | 
         | My experience is building an exceptionally large pub/sub
         | service, and pub/sub starts nice until you really care about
         | reliability. I made the mistake of patenting a protocol to sit
         | on top of WebSocket/SSE/MQTT as the ecosystem was a giant mess:
         | https://uspto.report/patent/grant/11,228,626
         | 
         | What I learned was that by having E2E anti-entropy protocol is
         | that it's hard for pub/sub abstractions to not lose stuff or
         | lie. That protocol emerged precisely because years of
         | investment in pub/sub was a leaky bucket of issues.
         | 
         | Braid looks interesting. I'm using JSON marge as my algebraic
         | operator since I have an ordered stream of updates for my
         | system. http://www.adama-lang.org/blog/json-on-the-brain
        
         | mmzeeman wrote:
         | Very interesting. I've implemented something similar. It
         | evolved out of the co-browsing solution I developed for the
         | company I work for.
         | 
         | The solution uses mqtt. Clients subscribe to a topic on the
         | server, and the server publishes patches to update the view.
         | Patches can be incremental (patch against the last frame),
         | cumulative (patch agains the last keyframe) or a new keyframe.
         | It allows for server side rendered views. Multiple clients can
         | subscribe to the same view and keep in sync. See:
         | https://github.com/mmzeeman/zotonic_mod_teleview
        
           | mmzeeman wrote:
           | An example proof of concept application:
           | https://github.com/mmzeeman/zotonic_mod_doom_fire/
        
       | anderspitman wrote:
       | Great article. This stuff is fun to read about.
       | 
       | But none of this complexity is necessary.
       | 
       | Most of the world's "cloud" needs could be handled by each
       | extended family of 100-200 people have a couple nerdy cousins
       | administering a backed-up Nextcloud instance (maybe Sandstorm or
       | Cloudron if you really want to go nuts).
        
       | joelbondurant0 wrote:
        
       | politician wrote:
       | Mark mentioned the idea of using edge compute to process protocol
       | traffic. Do any CDNs support edge compute with WebSockets?
        
         | HALtheWise wrote:
         | Cloudflare Durable Objects should
        
       | jokoon wrote:
       | It's easy to point out that it's not trivial to make async stuff
       | with web technologies.
       | 
       | To be completely honest, when you look at the big picture, HTML
       | was designed to be a static document format.
       | 
       | I really wish some new format or standard would be built from the
       | ground up. HTML JS was never a good format, it just got popular
       | to fight microsoft.
        
         | spullara wrote:
         | Microsoft basically invented the modern web with
         | XMLHttpRequest.
         | 
         | https://en.wikipedia.org/wiki/XMLHttpRequest#History
        
         | austincheney wrote:
         | That might have been true a decade ago, but no longer. With a
         | bit of practice wiring things async is trivial easy. You have
         | plenty of options now with http2, web sockets, and SSE. The
         | hardest part, by far, in any of this is certificate management
         | for the mandatory push to TLS for everything. Even that is much
         | easier now with OpenSSL almost everywhere and Let's Encrypt.
        
         | jcelerier wrote:
         | https://www.canonic.com/
        
       | ShoveItHN wrote:
       | Interesting. I'm writing an application that will control devices
       | over HTTP with a REST-style API (defined in OpenAPI). But we also
       | want those devices to be able to alert the controlling
       | application to events without being polled. This won't be a large
       | datastream, but rather the occasional update of progress or
       | notification of a state change.
       | 
       | I was considering Websockets or MQTT (or both), so server-sent
       | events sound like a direct and possibly superior competitor. But
       | from a design standpoint, what do you do? Just do a GET on some
       | general "status" endpoint to open this SSE stream and then have
       | the server send everything down this pipe indefinitely?
        
         | samwillis wrote:
         | Yes, it's just a GET that stays open, super simple. There are
         | various client libs that support SSE outside of browsers, worth
         | having a look if there is one for the language you are using.
        
           | ShoveItHN wrote:
           | Thanks! I haven't done much network programming.
           | 
           | While this SSE channel stays open, the controlling app will
           | need to be able to continue to do additional traditional GET,
           | POST, etc. calls to the server. How are responses to those
           | distinguished from data coming in from SSE?
        
             | drothlis wrote:
             | Same way that if you make 2 "normal" GETs simultaneously to
             | the same server the responses don't get mixed up, i.e.
             | they'll be separate HTTP Connections which are separate TCP
             | connections:
             | 
             | > Each HTTP connection maps to one underlying transport
             | connection.
             | 
             | -- https://httpwg.org/http-core/draft-ietf-httpbis-
             | messaging-la...
             | 
             | TCP uses "port numbers" to identify different connections.
             | 2 different connections from your PC to the same web server
             | will use 2 different "source" ports. A port is just a
             | number in the TCP header. https://en.wikipedia.org/wiki/Tra
             | nsmission_Control_Protocol#...
             | 
             | HTTP/1.1 added pipelining, so you can make several requests
             | on the same TCP connection before receiving a response. But
             | the (complete) responses must arrive in the same order of
             | the requests so it doesn't work for SSE.
             | 
             | HTTP/2 added request & response multiplexing on the same
             | TCP connection. But (according to the OP) there are some
             | limitations that affect SSE.
        
             | eldelshell wrote:
             | SSE has its own API (EventSource), it's not a normal
             | fetch/ajax request.
             | 
             | https://developer.mozilla.org/en-US/docs/Web/API/Server-
             | sent...
        
         | toomim wrote:
         | Your use-case sounds perfect for Braid: https://braid.org
         | 
         | This works like SSE, but is designed specifically to articulate
         | changes to the state of HTTP/REST resources.
         | 
         | If you're in Javascript, you can use the braidify library:
         | https://www.npmjs.com/package/braidify
        
         | flyinprogrammer wrote:
         | You might also checkout https://rsocket.io/
        
       | romaniv wrote:
       | I understand that right now people just want some way to make
       | pages update with minimum fuss, but when you start talking about
       | extending HTTP (even more), that automatically brings up the
       | question of whether you're solving the wrong problem.
       | 
       | > What's the best way to do pub/sub on the Web?
       | 
       | I think it's the wrong question. Or at least it will become the
       | wrong question at some point. Should we be pushing for web
       | technologies even when we need communication models that the Web
       | clearly was not designed for? After having used NATS for some
       | things, web services, web sockets and all other related stuff
       | feels archaic and byzantine. Too much ducktape on top of a very
       | simple, but limited idea of hyperlinked documents.
        
       | nickjj wrote:
       | I don't know why but when I read this from the article:
       | 
       |  _> Because WebSockets is effectively a blank canvas, there are a
       | lot of choices to be made when designing a protocol on top of it,
       | and no one way of doing it has yet gained momentum._
       | 
       | It immediately reminded me of Flash.
       | 
       | Flash was basically a blank canvas where you can do just about
       | anything. Turns out that's not a very good model for a number of
       | reasons -- one of which being it turns everything you do into a
       | snowflake and you need to invent your own patterns and
       | abstractions instead of leaning on an extremely well thought out
       | but more limited approach that's been vetted for many years
       | before Flash was a thing.
       | 
       | I don't think WebSockets are really bad but it makes me
       | internally wince whenever I see tech stacks trying to push using
       | them for everything, even for transitioning between pages with no
       | broadcast mechanism. Now I see part of the allure though. If
       | you're a language or framework maker you get to make decisions at
       | the protocol level instead of sticking to decades of standards
       | which is the awesomeness of HTTP.
       | 
       | I'm all for sprinkling in tiny bits of WebSockets when it makes
       | sense, ie. doing actual pub/sub things like showing notifications
       | or showing messages like "4 new people commented on your post,
       | click here to show them". In the same way that it felt ok to use
       | a little bit of Flash back in the day for specific functionality
       | instead of throwing out everything and trying to make your entire
       | site in Flash.
        
         | jcelerier wrote:
         | > Flash was basically a blank canvas where you can do just
         | about anything. Turns out that's not a very good model for a
         | number of reasons -- one of which being it turns everything you
         | do into a snowflake and you need to invent your own patterns
         | and abstractions instead of leaning on an extremely well
         | thought out but more limited approach that's been vetted for
         | many years before Flash was a thing.
         | 
         | yet we're in 2022 and the only things that are remotely
         | competitive with what Flash allowed 15 years ago, are some
         | games put in WASM blobs (which will "work" until $BROWSER
         | deprecates some API in two years).
        
         | PragmaticPulp wrote:
         | WebSockets are actually fantastic for providing low overhead
         | and high flexibility. It's really not difficult to use any
         | number of modern frameworks to do things like encode and decode
         | from wire formats or even multiplex across the channel.
         | 
         | WebSockets shouldn't be approached as a "from scratch"
         | communication method unless you have very specific needs or
         | your application is dead simple. Everyone else should take
         | advantage of the numberous libraries available to help with the
         | basics.
         | 
         | > I don't think WebSockets are really bad but it makes me
         | internally wince whenever I see tech stacks trying to push
         | using them for everything, even for transitioning between pages
         | with no broadcast mechanism.
         | 
         | I'm not up to date with the less popular web frameworks. Which
         | frameworks do that?
        
           | nickjj wrote:
           | > I'm not up to date with the less popular web frameworks.
           | Which frameworks do that?
           | 
           | One of them is
           | https://github.com/phoenixframework/phoenix_live_view which
           | is a component of Phoenix / Elixir.
           | 
           | It will render your initial page over HTTP but then when you
           | transition pages or perform actions using various functions
           | it provides you it will send a diff of what's changed over
           | WebSockets. These actions could be limited to only the 1 user
           | using the site, such as clicking different links in a nav bar
           | to transition between page A and B.
           | 
           | The alternative to this is doing what other frameworks like
           | Rails has done with Hotwire Turbo where they make these types
           | of transitions or actions over HTTP. Turbolinks started to do
           | this back in 2015 or whenever it came out and now more
           | recently with Hotwire Turbo there's ways to only update a
           | tiny area of the page (again over HTTP) but it also
           | optionally supports using WebSockets for when you want to
           | broadcast things to all connected clients, such as updating a
           | counter somewhere or maybe showing a new reply on a blog
           | post, etc..
           | 
           | Laravel has Live Wire and there's also HTMX which is back-end
           | agnostic which all use HTTP for a bulk of their behaviors to
           | send server rendered HTML over the wire. I'm not a Laravel
           | developer but based on their docs they have a drop in
           | solution to handle broadcasting events with WebSockets on
           | demand too[0] so it can continue using HTTP for everything
           | except for when you want to broadcast events similar to
           | Hotwire Turbo in that regard.
           | 
           | [0]: https://laravel-livewire.com/docs/2.x/laravel-echo
        
             | lolinder wrote:
             | What exactly bugs you about LiveView's use of websockets?
             | I.e., is it performance, accessibility, aesthetics, or
             | something else?
             | 
             | I ask as someone who's very interested from a distance in
             | what Phoenix is doing with websockets, but hasn't gotten
             | into it enough to understand the cons.
        
               | rainbowlove wrote:
               | I'm not sure they understand that the copycats needed to
               | be built with non-websockets as a primary transport
               | because of the limitations of those other frameworks.
               | 
               | The BEAM and Erlang/OTP introduce an entirely different
               | set of considerations when it comes to maintaining and
               | managing on the order of millions of concurrent stateful
               | websockets connections.
               | 
               | The architecture of Plug/ Phoenix also means that, should
               | the community come to a conclusion that websockets are no
               | longer right, the transport mechanism is extensible, but
               | the underlying interface and semantics of your
               | application would be essentially unchanged. The Elixir
               | forums would be a better place to inquire about
               | websockets vs. SSE implementations for LiveView.
        
               | nickjj wrote:
               | > I'm not sure they understand that the copycats needed
               | to be built with non-websockets as a primary transport
               | because of the limitations of those other frameworks.
               | 
               | I do understand but I don't think it's practical to use
               | WebSockets to transport a page diff to move from page A
               | to B, or to update a little area of a page that's not
               | broadcast to anyone else.
               | 
               | The case to use WebSockets from Elixir has always been
               | "but think of what you don't need to send over the wire
               | like HTTP headers!"... until you want to know things like
               | what the user's agent is, IP address and a few other
               | common pieces of information that's normally stored in an
               | HTTP header. Now you need to explicitly add these to your
               | socket. It's easy (1 line of config) but these bytes
               | persist on the socket for every open connection.
               | 
               | Now it means if you have your million concurrent users
               | you have to make sure you have 1GB of memory on your
               | server that's dedicated to storing nothing but this
               | information. I'm being really optimistic here and only
               | accounting for 1kb of data per connected user.
               | Realistically a lot more memory will be used with a
               | million users.
               | 
               | In the grand scheme of things 1GB isn't a lot of memory,
               | especially if you're talking about a million users but
               | this is a problem HTTP doesn't have. This information
               | isn't persisted on a socket and stored in memory on your
               | server. It's part of the headers and that's it, your
               | server is done knowing about or caring about it once the
               | response is sent. If you had a million concurrent
               | visitors on your site your server wouldn't store anything
               | on a socket because no socket exists.
               | 
               | Likewise as soon as you start using `assigns` with
               | LiveView, anything you store on the socket is going to
               | actively take up memory on your server. Yes I know about
               | `temporary_assigns` but if you start using that
               | everywhere then you lose out on the "surgical diffs" and
               | you're back to transferring a bunch of stuff over the
               | wire because the state isn't saved on the socket for each
               | connected user.
               | 
               | The system contradicts itself and you end up needing a
               | real lot of memory on your server to hold this state or
               | you trade that off for storing only the essentials and
               | it's back to sending a lot over the wire. This also has a
               | bunch of mental complexity because you as the end user
               | who builds the app needs to think about these things all
               | the time.
               | 
               | It's much more than "think" too. You end up in a world
               | where you can go out of memory and your server will crash
               | unless you carefully pre-estimate / provision resources
               | based on a specific traffic load to know how much memory
               | it will take. You can go out of memory with a lot less
               | than a million connections too, especially if you forget
               | to make something a temporary assigns which the compiler
               | won't help you with. With HTTP can throw a cache in front
               | of things and now you're bound by how fast your web
               | server can write out responses. HTTP also has decades of
               | support around efficiently scaling, serving, compressing,
               | CDNs, etc..
               | 
               | Then on top of that, if a user loads your site and
               | there's a 3 second blip in the network after it's loaded
               | then they're going to see loading bars because the
               | WebSockets connection was dropped and the socket needs to
               | reconnect. With HTTP this isn't a problem because once
               | you load the page the response is done and that's it. If
               | there's a blip in the network while reading a blog post
               | that's already loaded then it doesn't matter because the
               | content has already been served.
               | 
               | On paper being instantly aware of a dropped connection
               | sounds amazing, but in practice it creates a poor user
               | experience for anything that's read-only such as reading
               | a post on HN, or a GitHub issue, or a blog post or just
               | about anything that's not related to you actively
               | submitting a form. The world is fully of spotty internet
               | connections and HTTP is a master of hiding these blips
               | for a lot of cases.
               | 
               | You can build pretty interactive sites without WebSockets
               | too. If you bring up the network inspector on Google
               | Documents there's no WebSockets connection open. I don't
               | know what Google is doing here but I notice a lot of big
               | sites don't use WebSockets.
               | 
               | For example AWS's web console has a bunch of spots where
               | you can get updates but there's no WebSockets connection
               | open. The same goes for GMail, GitHub (real time issue
               | comments) and others.
               | 
               | That's not to say WebSockets are all around bad, it's
               | just interesting that even for something as collaborative
               | and real-time as Google Docs it can be done without them
               | while having an excellent user experience.
               | 
               | NOTE: I would never solely base a tech decision on what
               | these companies are using for their tech but it's at
               | least interesting they've all chosen not to use
               | WebSockets for whatever reasons they had.
               | 
               | > The architecture of Plug/ Phoenix also means that,
               | should the community come to a conclusion that WebSockets
               | are no longer right, the transport mechanism is
               | extensible
               | 
               | What would happen if the transport layer went back to
               | HTTP? Right now with LiveView you have to rewrite your
               | entire front-end to not depend on plugs / controllers and
               | now you have to re-create this idea of a plug-like system
               | in WebSockets (such as using on_mount, etc.). All of this
               | new code and patterns to solve the same things that were
               | solved for decades with HTTP -- or let's say ~7 years
               | with Phoenix pre-LiveView.
               | 
               | Those are only a few things related to the problems you
               | face when using WebSockets for everything. I still think
               | WebSockets are good but personally I wouldn't use a
               | framework that pushes to use it for everything, the world
               | isn't connected over a local connection with 1ms of
               | latency and 0% packet loss. Plus, WebSockets powered
               | sites tend to feel pretty sluggish for me. It's like
               | browsers are less optimized to deal with painting changes
               | emit by a socket, I don't have a scientific measurement
               | to show you here but I can feel it on sites that use
               | WebSockets to handle things like page navigation. There
               | was a site I saw like 8 months ago where it showed both a
               | Hotwire Turbo and Stimulus Reflex (WebSockets) demo page
               | hosted on the same server to do pagination on a table and
               | clicking around the WebSockets version felt slower even
               | with the same latency to the server.
               | 
               | Speaking of "feel", I made a video about how Topbar from
               | Phoenix makes page transitions with a fast connection
               | feel slower a few weeks ago
               | https://nickjanetakis.com/blog/customizing-topbar-to-add-
               | a-d.... This is unrelated to WebSockets but I'm just
               | saying it's pretty easy to see inefficiencies around user
               | experience in ways that aren't mathematically proven.
        
         | dpeck wrote:
         | | Flash was basically a blank canvas where you can do just
         | about anything. Turns out that's not a very good model for a
         | number of reasons
         | 
         | I don't think of this as a bad thing. There was exactly a lot
         | of what you say happening around that time, but the time when
         | Flash was biggest was also a time of massive creativeness on
         | the web. I think we're missing some of that now, and I'm more
         | than ok with our collective "pendulum" swinging back towards
         | the blank canvas than the overfit tech world we have today.
        
       | anoplus wrote:
       | SSA 24q1H waec aqgwfxd
        
       ___________________________________________________________________
       (page generated 2022-02-20 23:01 UTC)