I tried out server side events, but they are still quite troubling with the lack of headers and cookies. I remember I needed some polyfill version which gave more issues.
That is wrong. Edit: Actually it seems correct (a javascript problem, not SSE problem) but it's a non-problem if you use a parameter for that data instead and read it on the server.
You cannot send custom headers when using the built-in EventSource[1] constructor, however you can pass the ‘include’ value to the credentials option. Many polyfills allow custom headers.
However you are correct that if you’re not using JavaScript and connecting directly to the SSE endpoint via something else besides a browser client, nothing is preventing anyone from using custom headers.
WebSockets support compression (ofc, the article goes on to detail this & point out flaws. I'd argue that compression is not generally useful in web sockets in the context of many small messages, so it makes sense to be default-off for servers as it's something which should be enabled explicitly when necessary, but the client should be default-on since the server is where the resource usage decision matters)
I don't see why WebSockets should benefit from HTTP. Besides the handshake to setup the bidirectional channel, they're a separate protocol. I'll agree that servers should think twice about using them: they necessitate a lack of statelessness & HTTP has plenty of benefits for most web usecases
Still, this is a good article. SSE looks interesting. I host an online card game openEtG, which is far enough from real time that SSE could potentially be a way to reduce having a connection to every user on the site
1) More complex and binary so you cannot debug them as easily, specially on live and specially if you use HTTPS.
2) The implementations don't parallelize the processing, with Comet-Stream + SSE you just need to find a application server that has concurrency and you are set to scale on the entire machines cores.
3) WebSockets still have more problems with Firewalls.
I can’t find any downsides of SSE presented. My experience is that they’re nice in theory but the devils in the details. The biggest issue being that you basically need http/2 to make them practical.
Take this for what it's worth, but I see you share rupy on pretty much every thread that mentions WebSockets, and I click on the link pretty much every time, and I still have basically no idea what it is. Documentation probably isn't your priority at the moment, but even just a couple paragraphs could go a long way.
I had the same impression as you. I want to learn more about fuse but even their "sales pitch" page is in the same tone of "fuse can do a lot" (and that's fine, I'm sold!) except there is very little documentation at the moment.
I know, I just go by "the code is so small, you should have time to read it".
rupy is a minimalist, from scratch, HTTP app-server that uses non-blocking IO so it can scale comet-stream (SSE or not) which is much better than WebSockets: https://news.ycombinator.com/item?id=30313403
I will never make projects that you just download and double click to run.
I want my users to understand how it works more than I want them to use it!
The TCP stack can give you that info if you are lucky in your topography but generally you cannot rely on this working 100%.
The way I solve it is to send "noop" messages at regular intervals so that the socket write will return -1 and then I know something is off and reconnect.
One example where i found it to be not the perfect solution was with a web turn-based game.
The SSE was perfect to update gamestate to all clients, but to have great latency from the players point of view whenever the player had to do something, it was via a normal ajax-http call.
Eventually I had to switch to uglier websockets and keep connection open.
With HTTP/2, the browser holds a TCP connection open that has various streams multiplexed on top. One of those streams would be your SSE stream. When the client makes an AJAX call to the server, it would be sent through the already-open HTTP/2 connection, so the latency is very comparable to websocket — no new connection is needed, no costly handshakes.
With the downsides of HTTP/1.1 being used with SSE, websockets actually made a lot of sense, but in many ways they were a kludge that was only needed until HTTP/2 came along. As you said, communicating back to the server in response to SSE wasn’t great with HTTP/1.1. That’s before mentioning the limited number of TCP connections that a browser will allow for any site, so you couldn’t use SSE on too many tabs without running out of connections altogether, breaking things.
>no new connection is needed, no costly handshakes.
No new connection and no low-level connection (TCP, TLS) handshakes, but the server still has to parse and validate the http headers, route the request, and you'd probably still have to authenticate each request somehow (some auth cookie probably), which actually may start using a non-trivial amount of compute when you have tons of client->server messages per client and tons of clients.
I wonder if websockets "accidentally" circumvented HTTP2's head-of-line blocking problem and therefore appeared to have better latency:
SSE streams are multiplexed into a HTTP2 stream, so they can suffer from congestion issues caused by unrelated requests.
In contrast, HTTP2 does not support websockets, so each websocket connection always has its own TCP connection. Wasteful, but ensures that no head-of-line blocking can occur.
So it might be that switching from SSE to websockets gave better latency behaviour, even though it had nothing to do with the actual technologies.
Of course, this issue should be solved anyway with HTTP3.
> Wasteful, but ensures that no head-of-line blocking can occur.
That’s not how head-of-line blocking works. Just having a single stream doesn’t guarantee no blocking. It’s not really about unrelated requests getting in the way and sucking up bandwidth (that’s a separate issue, and arguably applies regardless of how many TCP connections you have), head-of-line blocking is about how TCP handles retransmission of lost packets. Websocket suffers from head-of-line blocking too, which is a reason that WebTransport is being developed.
Certainly, if you have other requests in flight, you could have head-of-line blocking because of a packet that was dropped in a response stream that isn’t related to your SSE stream, but this only applies if there’s packet loss, and the packets that were lost could just as easily be SSE’s or websocket’s.
I agree that HTTP/3 should solve the issue of head-of-line blocking being caused by packets lost from an unrelated stream, but it doesn’t prevent it from occurring entirely.
My understanding (which could be wrong) is that WebTransport is supposed to offer the ability to send and receive datagrams with closer to UDP-level guarantees, allowing the application to continue receiving packets even when some go missing, and then the application can decide how to handle those missing packets, such as asking for retransmission. Getting an incomplete stream at the application level is what it takes to entirely avoid head-of-line blocking.
As alluded to earlier, there is zero head-of-line blocking if there is no packet loss. Outside of congested networks or the lossy fringes of cell service, I really wonder how much of an issue this is. I’m skeptical that it adds any latency for SSE vs websocket in the average benchmark or use case. The latency should be nearly identical. Your comment seems predicated on it definitely being worse, but based on what numbers? I admit it’s been a couple of years since I measured this myself, but I came away with the conclusion that websockets are massively overrated. There are definitely a handful of use cases for websockets, but… it shouldn’t be the tool everyone reaches for.
HTTP/3 is really meant to be an improvement for a small percentage of connections, which is a huge number of people at the scale that Google operates at. I don’t think there are really any big downsides to HTTP/3, so I look forward to seeing it mature, become more common, and become easier to find production grade libraries for.
> Certainly, if you have other requests in flight, you could have head-of-line blocking because of a packet that was dropped in a response stream that isn’t related to your SSE stream, but this only applies if there’s packet loss, and the packets that were lost could just as easily be SSE’s or websocket’s.
That was what I meant. Yes, head-of-line blocking can occur everywhere there is TCP, but with HTTP2, the impact is larger due to the (otherwise very reasonable) multiplexing: When a HTTP2 packet is lost, this will stall all requests that are multiplexed into this connection, whereas with websocket, it will only stall the websocket connection itself.
>the browser holds a TCP connection open that has various streams multiplexed on top. One of those streams would be your SSE stream. When the client makes an AJAX call to the server, it would be sent through the already-open HTTP/2 connection
Very interesting ! I honestly didn't know that, or even think about it like that ! #EveryDayYouLearn :)
I think it comes down to whether your your communication is more oriented towards sending than receiving. If the clients receive way more than they send, then SSE is probably fine, but if it's truly bidirectional then it might not work as well.
It's not the most well documented but it's the smallest implementation while still being one of the most performant so you can learn more than just SSE.
I managed to get through almost all middle men by using 2 tricks:
1) Push a large amount of data on the pull (the comet-stream SSE never ending request) response to trigger the middle thing to flush the data.
2) Using SSE instead of just Comet-Stream since they will see the header and realize this is going to be real-time data.
We had 99.6% succes rate on the connection from 350.000 players from all over the world (even satellite connections in the Pacific and modems in Siberia) which is a world record for any service.
The world record is not the 1.100 concurrent users per machine (T2 small then medium on AWS) we had at peak, but the 99.6% connections we managed. All other multiplayer games have ~80% if they are lucky!
350.000 was the total number of players during 6 years.
You don't need HTTP/2 to make SSE work well. Actually the HTTP/2 TCP head-of-line issue and all the workarounds for that probably make it harder to scale without technical debt.
The mistake they did was to assume only one TCP socket should be used; the TCP has it's own head-of-line limitations just like HTTP/1.1 has if you limit the number of sockets (HTTP/1.1 had 2 sockets allowed per client, but Chrome doesn't care...) it's easily solvable by using more sockets but then you get into concurrency problems between the sockets.
That said if you, like SSE on HTTP/1.1; use 2 sockets per client (breaking the RFC, one for upstream and one for downstream) you are golden but then why use HTTP/2 in the first place?
HTTP/2 creates more problems than solutions and so does HTTP/3 unfortunately until their protocol fossilizes which is the real feature of a protocol, to become stable so everyone can rely on things working.
In that sense HTTP/1.1 is THE protocol of human civilization until the end of times; together with SMTP (the oldest protocol of the bunch) and DNS (which is centralized and should be replaced btw).
Sure but then HTTP/3 is still binary and it's in flux meaning most routers don't play nice with it yet and since HTTP/1.1 works great for 99.9% of the usecases I would say it's a complete waste of time, unless you have some new agenda to push.
Really people should try and build great things on the protocols we have instead of always trying to re-discover the wheel, note: NOT the same as re-inventing the wheel: http://move.rupy.se/file/wheel.jpg
While I agree, we shouldn't discount one less RTT for encrypted connections. Latency is a problem that never really goes away, and we can only try to reduce RTTs.
For FANG scale, a 1% performance improvement for certain services has measurable business results.
Take Snap. Say they reduced time to view a snap by 10ms. After 100 snaps that’s an additional 1 second of engagement. This could equate to an additional ad impression every week per user. Which is many millions of additional revenue.
HTTP/3 is E2E encrypted and built on UDP. What does “most routers don’t play nice with it yet” mean in that context? Do you mean middleware boxes/routers rather than end user routers?
"QUIC is a new always-encrypted general-purpose transport protocol being standardized at the IETF designed for multiplexing multiple streams of data on a single connection. HTTP/3 runs over QUIC and roughly replaces HTTP/2 over TLS and TCP. QUIC combines the cryptographic and transport handshakes in a way to allow connecting to a new server in a single round trip and to allow establishing a resumed connection in zero round trips, with the client sending encrypted application data in its first flight. QUIC uses TLS 1.3 as the basis for its cryptographic handshake.
This talk will provide an overview of what the QUIC protocol does and how it works, and then will dive deep into some of the technical details. The deep dive will focus on security-related aspects of the protocol, including how QUIC combines the transport and cryptographic handshakes, and how resumption, including zero-round-trip resumption works. This will also cover how QUIC’s notion of a connection differs from the 5-tuple sometimes used to identify connections, and what QUIC looks like on the wire.
In addition to covering details of how QUIC works, this talk will also address implementation and deployment considerations. This will include how a load balancer can be used with cooperating servers to route connections to a fleet of servers while still maintaining necessary privacy and security properties. It will also look back at some of the issues with HTTP/2 and discuss which ones may need to be addressed in QUIC implementations as well or are solved by the design of QUIC and HTTP/3."
I think the common definition of e2e encryption covers user-to-user communication, so I'm confused how a transport protocol can offer e2e encryption at all (it would only do so if Quic is used over p2p between users, but that's a property of the application).
But even if the definition were different, http+tls would also be e2e encrypted (if used in conjunction which it pretty much always is).
I appreciate Quic but from a security perspective I don't see how it's different to what we've had for at least a decade.
The difference is that the protocol itself is also encrypted (not just the application layer). In other words middleware can’t ossify the QUIC protocol and you’re not reliant on middleware to do anything other than route UDP (which lets you do whatever you want to the protocol itself).
TCP is not perfect. There is ambiguity between the acknowledgement of a segment and the retransmission of a segment that we have tried to address with extensions and heuristics. It can introduce latency for upper protocols which are comprised of fixed-length messages. SACK reneging is a crime against humanity.
It's amazing that we've been able to adapt the protocol in a backwards-compatible fashion for over 30 years, but QUIC addresses problems with TCP in ways that could not be done in a backwards-compatible fashion. Personally I wish the protocol were simpler, but I lack the expertise to say what should be removed.
If people had tried to build great things on the protocols we have instead of re-discovering the wheel, we'd still have gopher, FTP and telnet for most things. Technology evolves and that's a good thing.
> and DNS (which is centralized and should be replaced btw
So much nonsense in a single paragraph, amazing.
If anything DNS is less centralized then http and SMTP.
Its a surprisingly complicated system for what it does because of all the caching etc, but calling it more centralized then http is just is just ignorant to a silly degree
Your license makes some sense, but it seems to include a variable perpetual subscription cost via gumroad. Without an account (assuming I found the right site), I have no idea what you would be asking for. I recommend making it a little clearer on the landing page.
That's said, it's very cool. Do you have a development blog for Meadow?
No, no dev log but I'll tell you some things that where incredible during that project:
- I started the fuse project 4 months before I set foot in the Meadow project office (we had like 3 meetings during those 4 months just to touch base on the vision)! This is a VERY good way of making things smooth, you need to give tech/backend/foundation people a head start of atleast 6 months in ANY project.
- We spent ONLY 6 weeks (!!!) implementing the entire games multiplayer features because I was 100% ready for the job after 4 months. Not a single hickup...
- Then for 7 months they finished the game client without me and released without ANY problems (I came back to the office that week and that's when I solved the anti-virus/proxy cacheing/buffering problem!).
I think Meadow is the only MMO in history so far to have ZERO breaking bugs on release (we just had one UTF-8 client bug that we patched after 15 minutes and nobody noticed except the poor person that put a strange character in their name).
Open-source also means the source is open, what you are looking for is free and honestly nothing is free... if you have a better term I'm open for suggestions.
But really open-source (as in free) is the misnomer here, it should be called free open-source, or FOSS as some correctly name it.
That battle has been fought already, and the accepted term is "source available", not "open source". (And gnu adds Free or "libre" software, which is software licence in a way that tries to ensure the "four freedoms" for all downstream users of software - such as freedom zero - the right to run software (no need for eg: cryptographic signature/trusted software - without a way for the user to define trust).
FOSS or F/OSS is a combination of Free (as defined by the FSF) and Open Source (as defined by the OSI) (the last S is Software), which recognizes that the two terms, while they come from groups with different ideological motivations, refer to approximately the same substantive licensing features and almost without exception the same set of licenses.
Personally, while I appreciate the difference from a promotion-of-FOSS point of view, I find it obnoxious that FOSS idealists think they can dictate the usage of the generic phrase “open source” and start these kinds of arguments in threads where non-completely-free software whose source is open comes up. We haven’t all agreed on your terminology, and the argument is not “settled” except in the minds of the folks who think everyone should be on board with making this purity distinction. Some people find the distinction uninteresting and don’t need to bother themselves with the ideological argument or agree to its terminology. And trying to be the arbiters of language is not a good look for the “information wants to be free” crowd.
You give ‘em whatever you want. :) I think I’ll publish my next open source project with a license that permits no use whatsoever. Code provided for entertainment purposes only.
Since the several decades before a few people decided to co-opt it for strategic political reasons. You apparently don’t remember the arguments over whether they should be called “free software” or “open source.” Both terms were already in use. I grew up downloading shareware, some of which was open source and some of which was not. It almost universally came with a limited use license and a request for some money if you used it. This is how Unix started too. Limited license with open source code. You can send your changes back to us but you can’t distribute them.
RMS has even published an essay talking about how the term “open source” is a poor choice because it has an obvious common sense definition that means “you can see the source.”
While I get and support the intent, I don't like this usage of the name of the MIT license. I personally like the license because it tells me at a glance that I can use it for any purpose, commercial or otherwise, as long as the copyright and license is included and that there is no warranty. That's it, no complications, no other demands, no "if it makes X money or not", just I include the copyright and license terms and that's it, I can use the software whichever way I like.
Your license is not that. You have extra conditions that add complexity. I can no longer go "oh like MIT" and immediately use it for any purpose, because you require extras especially if I were to make money. That seems completely against the spirit of the simplicity of the MIT license which says you can do whatever you like, commercial or otherwise, as long as the copyright and license are included.
I think you should make your own license that includes the text of the MIT license, except removing the irrelevant parts (ie the commercial aspects include a caveat about requiring payment). You can still have a separate line of text explaining that the license is like the MIT license but with XYZ changes (basically the text you have now). But the license is not the MIT license and you should therefore have a separate license text that spells it out exactly. Not "its this, except scratch half of it because these additional terms override a good chunk of it".
Ok, I agree but then I also have less time to work on real things and honestly I feel the whole legal/money part of our civilization is a huge waste of time in the face of energy problems that can't go away (2nd law of thermodynamics and sunlight + photosyntesis) and that my platform tries to help with elegantly by being the most efficient solution for MMO networking.
I'm also sad that nobody has solved this license problem yet, there is obviously a need for it. Sometimes time solves all problems though, so I probably just have to wait a while and somebody makes exactly the right license.
But I'm going to allocate some time if somebody who is willing to pay approaches me with the same concerns (it's actually why I switched to MIT in the first place, Unreal does not allow you to use client plugins that are LGPL)...
> then I also have less time to work on real things
What? To keep your existing license you copy the text of the MIT license, add the statement about requiring a logo and remove the parts about being able to use the code commercially, and add an extra paragraph that has the text you already have: to use commercially you have to sponsor. It’s not about changing your terms, it’s about being clear about what license applies. Hybrid with MIT and other implies that the MIT license somehow applies yet it does not since your “other” invalidates a chunk of what the MIT license allows. Just removing those bits and not calling it MIT is enough.
If that significantly cuts into your time to do other stuff then I don’t know what to say.
> if somebody who is willing to pay approaches me with the same concerns
I’m not concerned about the license per se. It wouldn’t stop me from paying if I wanted to use your software. It’s just that to everyone looking, before even evaluating it, you’re sending a dishonest message, that somehow the MIT license applies when it clearly does not.
I would create a license.txt file that contains a copy of the MIT license text with the commercial use phrasing removed, the need for displaying logo added a second paragraph before the warranty disclaimer stating that you may use the software commercially so long as you sponsor (same text you already have). Then I would link it from the readme with an explanation: proprietary license that is similar to the MIT license except with the conditions of logo and for commercial use requiring sponsorship (existing text more or less). Clear, simple and should take you no more than ten minutes to fix.
My objection is that you are claiming it’s under MIT license and using the MIT licenses name recognition, while applying changes that very clearly make it not MIT license at all.
"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:"
Became
"Permission is hereby granted, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software, including the rights to copy, modify, merge, publish and/or distribute the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:"
And then I list the stuff...
1) You have to show the logo on startup.
2) You have to sponsor the fuse tier on gumroad while you are using the Software, or any derived Software, commercially:
3) The .html and graphics are proprietary examples except the javascript in play.html
4) The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
it feels completely meaningless to put it that way... laws are really the most superficial waste of time, it only took 5 minutes to edit but it's a lifetime of trouble!
But thanks I guess, if it works... but you only know that later... possibly eons later!
Can you explain what you mean here? What was your peak active user count, what was peak per server instance, and why you think that beats anything else?
Agreed, I'm curious as well. We load tested with real-clients faux-users, up to 1 million concurrent. And only stopped at 1 million because the test was becoming cost prohibitive.
Under Performance. Per watt the fuse/rupy platform completely crushes all competition for real-time action MMOs because of 2 reasons:
- Event driven protocol design, averages at about 4 messages/player/second (means you cannot do spraying or headshots f.ex. which is another feature in my game design opinion).
- Java's memory model with atomic concurrency parallelism over shared memory which needs a VM and GC to work (C++ copied that memory model in C++11, but it failed completely because they lack both VM and GC, but that model is still to this day the one C++ uses), you can read more about this here: https://github.com/tinspin/rupy/wiki
These keep the internal latency of the server below maybe 100 microseconds at saturation, which no C++ server can handle even remotely, unless they copy Java's memory model and add a VM + GC so that all cores can work on the same memory at the same time without locking!
You can argue those points are bad arguments, but if you look at performance per watt with some consideration for developer friendlyness, I'm pretty sure in 100 years we will still be coding minimalist JavaSE (or some copy without Oracle) on the server and vanilla C (compiled with C++ compiler gcc/cl.exe) on the client to avoid cache misses.
Not other than the one linked in the comment above. I have been reaching out to EVERYONE, and nobody can explain this to me, but I'll implement it myself soon so I can explain it.
My intuition tells me the VM provides a layer decoupled from the hardware memory model so that there is less "friction" and the GC is required to reclaim shared memory that C++ would need to "stop the world" to reclaim anyhow! (all concurrent C++ objects leaks memory, see TBB concurrent_hash_map f.ex.) That means the code executes slower BUT the atomics can work better.
As I said; for 5 years I have been searching for answers from EVERYONE on the planet and nobody can answer. My guess is that this is so complicated, only a handfull can even begin to grook it, so nobody wants to explain it because it creates alot of wasted time.
The usual reaction is: Java is written in C, so how can Java be faster than C? Well I don't know how but I know it's true because I use it!
So my answer today is: Java is faster than C if you want to share memory between threads directly efficiently because you need a VM with GC to make the Java memory model (which everyone has copied so I guess it must be good?) work!
But no guarantees... you never get those with C/C++, I stopped downloading C/C++ code from the internet unless it has 100+ proved users! So stb/ttf and kuba/zip are my only dependencies.
> My intuition tells me the VM provides a layer decoupled from the hardware memory model so that there is less "friction" and the GC is required to reclaim shared memory that C++ would need to "stop the world" to reclaim anyhow! (all concurrent C++ objects leaks memory, see TBB concurrent_hash_map f.ex.) That means the code executes slower BUT the atomics can work better.
I dunno about the GC bits; after all object pools are a thing in C++ so you have a consistent place (getting a new object) where reclamation of unused objects can be performed.
I think it might be down to mutex locking. In a native program, a failure to acquire the mutex causes a context-switch by performing a syscall (OS steps in, flushes registers, cache, everything, and runs some other thread).
In a VM language I would expect that a failure to acquire a mutex can be profiled by the VM with simple heuristics (Only one thread waiting for a mutex? Spin on the mutex until its released. More than five threads in the wait queue? Run some other thread).
Its a lot easier to scale than websockets where you need a pub sub solution and a controller to published shared state changes. See is really simply incomparision
Couldn't find a license file in the root folder of that github. I found a license in a cpp file buried in the sec folder. You should consider putting the licensing for this kind of project in a straightforward and locatable place.
I just found out gumroad pays VAT on recurring payments a couple of weeks ago.
We probably need a new license though because piggybacking on MIT (or any other license) like I try to do is rubbing people the wrong way.
But law and money are my least favourite passtimes, so I'm going to let somebody else do it first unless somebody is willing to force this change by buying a license and asking for a better license text.
Your source-available projects. Nothing wrong with licensing your work that way (in the sense that you can make that choice, not in the sense that I think its a good idea) but please don't muddle the term "open source".
Well technically rupy is open-source (ALGPL, yet another license that still doesn't exist) and since fuse (source-available) is built on top, you can maybe call it open-source, specially since rupy is like 90% of the code.
Personally i use mqtt over websockets, paho[0] is a good js library. It support last will for dc's and the message queue design makes it easy to think of and debug. There also a lot of mq brokers that will scale well.
I have used SSEs extensively, I think they are brilliant and massively underused.
The one thing I wish they supported was a binary event data type (mixed in with text events), effectively being able to send in my case image data as an event. The only way to do it currently is as a Base64 string.
In my case I was aiming for low latency with a dynamically generated image. To send a url to a saved image, I would have to save it first to a location for the browser to download it form. That would add at least 400ms, probably more.
Ultimately what I did was run an SSE request and long polling image request in parallel, but that wasn’t ideal as I had to coordinate that on the backend.
That’s actually not too far from what we do. The image is created by a backend service with communication (queue and responses) to the front end servers via Redis. However rather than saving the image in its entirety to Redis, it’s streamed via it in chunks using LPUSH and BLPOP.
This lets us then stream the image as a steaming http response from the front end, potentially before the jpg has finished being generated on the backend.
So from the SSE we know the url the image is going to be at before it’s ready, and effectively long poll with a ‘new Image()’.
Quite true, however from memory Django doesn’t (or didn’t) support gzip on streaming responses and as we host on Heroku we didn’t want to introduce another http server such as Nginx into the Heroku Dyno.
As an aside, Django with Gevent/Gunicorn does SSE well from our experience.
I usually use SSEs for personal projects because they are way more simple than WebSockets (not that those aren't also simple) and most of the time my web apps just need to listen for something coming from the server and not bidirectional communication.
So do I understand correctly that when using SSE, the login cookie of the user is not automatically sent with the SSE request like it is with all normal HTTP requests? And I have to redo auth somehow?
I’m a huge fan of SSE. In the first chapter of my book Fullstack Node.js I use it for the real-time chat example because it requires almost zero setup. I’ve also been using SSE on https://rambly.app to handle all the WebRTC signaling so that clients can find new peers. Works great.
Did research on SSE a short while ago. Found out that the mimetype "text/event-stream" was blocked by a couple of anti-virus products. So that was a no-go for us.
These days I feel like the only way to win against poorly designed antiviruses and firewalls is to—ironically enough—behave like malware and obfuscate what's going on.
It's not blocked. It's just that some very badly written proxies can try to buffer the "whole" response, and SSE is technically a never-ending file.
It's possible to detect that, and fall back to long polling. Send an event immediately after opening a new connection, and see if it arrives at the client within a short timeout. If it doesn't, make your server close the connection after every message sent (connection close will make AV let the response through). The client will reconnect automatically.
Or run:
while(true) alert("antivirus software is worse than malware")
My experience with sse is pretty bad. They are unreliable, don’t support headers and require keep-alive hackery. In my experience WebSockets are so much better.
Also ease of use doesn’t really convince me. It’s like 5 lines of code with socket.io to have working websockets, without all the downsides of sse.
> If you’re using tokens for auth and don’t want to use session cookies
That sounds like a self-inflicted problem. Even if you’re using tokens, why not store them in a session cookie marked with SameSite=strict, httpOnly, and secure? Seems like it would make everything simpler, unless you’re trying to build some kind of cross-site widget, I guess.
This is such an opaque response, I don't know what else could be said. If you're sending the same token to multiple websites, something feels very wrong with that situation. If it's all the same website, you can have multiple backends "mounted" on different paths, and that won't cause any problems with a SameSite cookie.
Then you need a single point of failure that is handling session validation. Without it part of your app might work even without your sessions storage.
SSE EventSource also has built-in auto-reconnect, and it doesn’t even need to support failover to long polling.
Neither of those being built into a third party websocket library are actually advantages for websocket… they just speak to the additional complexity of websocket. Plus, long polling as a fallback mechanism can only be possible with server side support for both long polling and websocket. Might as well just use SSE at that point.
Mind expanding on your experience and how are websockets more reliable than SSE? one of the main benefits of SSE is reliability from running on plain HTTP.
I've done both. One big one is Sse connections will eventually time out, and you WILL have to renegotiate, so there will be a huge latency spike on those events. They are easier in elixir than most pls, but honestly if you're using elixir, you might as well use phoenix's builtin we socket support.
I think it might be your ISP. For example one of my ISPs cut off my SSH connections no matter what I do. They simply dislike hanging SSH connections.
It's just random that your ISP like WebSockets more than long HTTP responses, and it can change in a heartbeat and for most people it will be different. As I said before 99,6% successful networking is an unheard of number for real-time multiplayer games.
I only care about that number, until you proove with hard stats and 350.000 real users from everywhere on the planet that WebSocket has 99,7% success rate, I'm not even going to flinch.
HTTP headers must be written before the body; so once you start writing the body, you can't switch back to writing headers.
Server-sent events appears to me to just be chunked transfer encoding [0], with the data structured in a particular way (at least from the perspective of the server) in this reference implementation (tl,dr it's a stream):
You understood correctly; I was mis-informed. Today I learned about the "Trailer" header. I'm curious how HTTP clients handle that. A client like window.fetch will resolve with a headers object-- does it include the trailers or not? I'd have to test it out.
socket.io doesn’t do as much as the bloat warrants. implementing the same features (heartbeats and reconnects) takes minimal code. socket.io was useful when certain browsers didn’t support websockets, now it’s used mostly by people scared of sockets imo
SSEs had a severe connection limit, something like 4 connections per domain per browser (IIRC), so if you had four tabs open then opening new ones would fail.
Browsers also limit the number of websocket connections. But, if you're using HTTP/2, as you should be, then the multiplexing means that you can have effectively unlimited SSE connections through a limited number of TCP connections, and those TCP connections will be shared across tabs.
(There's one person in this thread who is just ridiculously opposed to HTTP/2, but... HTTP/2 has serious benefits. It wasn't developed in a vacuum by people who had no idea what they were doing, and it wasn't developed aimlessly or without real world testing. It is used by pretty much all major websites, and they absolutely wouldn't use it if HTTP/1.1 was better... those major websites exist to serve their customers, not to conspiratorially push an agenda of broken technologies that make the customer experience worse.)
It appears to be 30 per domain, not “hundreds”, at least as of the time this answer was written. I didn’t see anything more recent that contradicted this.
In practice, this is unlikely to be problematic unless you’re using multiple websockets per page, but the limit of 6 TCP connections is even less likely to be a problem if you’re using HTTP/2, since those will be shared across tabs, which isn’t the case for the dedicated connection used for each websocket.
You can also make your HTTP/1.1 SSE endpoints available on multiple domains and have the client round-robin them. Obviously adds some complexity, but sometimes it's a tradeoff worth making for example if you're on lossy networks and trying to avoid HTTP/2 head-of-line blocking.
Right, but this article argues that SSE is simple and easy to debug on the wire - so is http1. Http2 is easy to set up, so are websockets, yet debugging the multiplexed http2 stream is is not that simple anymore.
The SSE connection limit is a nasty surprise once you run into it, it should have been mentioned.
> The SSE connection limit is a nasty surprise once you run into it, it should have been mentioned.
It does not apply to HTTP/2, as previously noted.
> Http2 is easy to set up, so are websockets, yet debugging the multiplexed http2 stream is is not that simple anymore.
I have literally never heard of anyone I personally know having to debug HTTP/2 on the wire. Unless you believe there are frequently bugs in the HTTP/2 implementation in your browser or the library you use, this just not a real concern. HTTP/2 has been around long enough that this is definitely not a concern of mine. I would be more worried about bugs with HTTP/3, since it is so new.
Websockets are also not especially easy to set up… they don’t work with normal HTTP servers and proxies, so you have to set up other infrastructure.
Which web servers do they not work with? They have worked everything I've used thus far (which admittedly aren't many): nginx, warp (Haskell's embedded server), relayd (OpenBSD), all with easy setup.
It also seems that compression for websockets is supported in all major browsers.
The article's argument seems to be that ws adds complexity, but this is present in pretty much all web servers already, the user needs not to deal with it. (HTTP2, too, requires the same type of complexity for that matter)
It's a beautifully simple & elegant lightweight push events option that works over standard HTTP, the main gotcha for maintaining long-lived connections is that server/clients should implement their own heartbeat to be able to detect & auto reconnect failed connections which was the only reliable way we've found to detect & resolve broken connections.
"the main gotcha for maintaining long-lived connections is that server/clients should implement their own heartbeat to be able to detect & auto reconnect failed connections"
It's not good enough in our experience, EventSource can still think it's connected when the server can no longer push data onto it. The periodic heartbeat to verify messages can still be sent on the connection is the only reliable way we've found to detect & autoretry failed connections.
I think SSE might make a lot of sense for Serverless workloads? You don't have to worry about running a websocket server, any serverless host with HTTP support will do. Long-polling might be costlier though?
the biggest drawback with SSE, even when unidirectional comm is sufficient is
> SSE is subject to limitation with regards to the maximum number of open connections. This can be especially painful when opening various tabs as the limit is per browser and set to a very low number (6).
It used to be 2 sockets per client, so now it's 6?
Well it's a non-problem, if you need more bandwith than one socket in each direction can provide you have much bigger problems than the connection limit; which you can just ignore.
the problem is multiple tabs. if you have, e.g. a bunch of Grafana dashboards open on multiple screens in different tabs (on same domain), you will exhaust your HTTP connection limit very quickly with SSE.
in most cases this is not a concern, but in some cases it is.
This isn’t a problem with HTTP/2. You can have as many SSE connections as you want across as many tabs as the user wants to use. Browsers multiplex the streams over a handful of shared HTTP/2 connections.
If you’re still using HTTP/1.1, then yes, this would be a problem.
> maybe each SSE response re-sends headers, which can be larger than the message itself?
That's (long) polling, not SSE. The only overhead for SSE are the "data", "event", etc pseudo header names and possibly some chunked-encoding markers. Both are tiny though.
Another way to solve it could be using a BroadcastChannel to communicate between tabs, do some kind of leader election to figure out which one should start the EventSource, and then have the leader relay the events over the channel.
Is it worth upgrading a long polling solution to SSE? Would I see much benefit?
What I mean by that is client sends request, server responds in up to 2 minutes with result or a try again flag. Either way client resends request and then uses response data if provided.
this is what i have been telling people for years, but its hard to get the word out there. usually every dev just reflexes without thinking to websockets when anything realtime or push related comes up.
SSEs are one of the standard push mechanisms in JMAP [1], and they're part of what make the Fastmail UI so fast. They're straightforward to implement, for both server and client, and the only thing I don't like about them is that Firefox dev tools make them totally impossible to debug.
Hmm! You're right that I hadn't looked it a while, so I checked before making the comment above. I'm still seeing the same thing I always have, which is "No response data available for this request". Possibly something is slightly wrong somewhere (though Chrome dev tools seem fine on the same), but you've given me something to look into, thanks!
That is interesting. I just tested it myself, and at least for my setup (Firefox on Mac on ARM), the events only showed up in the dev tools if the server closed the SSE connection... so, maybe Firefox still hasn't fully fixed this problem.
The Fastmail UI is indeed snappy, except when it suddenly decides it has to reload the page, which seems to be multiple times a day these days (and always when I need to search for a specific email). Can you make it do what one of my other favorite apps does: when there's a new version available, make a small pop up with a reload button, but don't force a reload (until maybe weeks later)?
It is, however, interesting to note that Fastmail’s webmail doesn’t use EventSource, but instead implements it atop fetch or XMLHttpRequest. An implementation atop XMLHttpRequest was required in the past because IE lacked EventSource, but had that been the only reason, it’d just have been done polyfill style; but it’s not. My foggy recollection from 4–5 years ago (in casual discussion while I worked for Fastmail) is that it had to do with getting (better?) control over timeout/disconnect/reconnect, probably handling Last-Event-ID, plus maybe skipping browser bugs in some older (now positively ancient and definitely unsupported) browsers. The source for that stuff is the three *EventSource.js files in https://github.com/fastmail/overture/tree/master/source/io.
I have always preferred SSE to WebSockets. You can do a _lot_ with a minuscule amount of code, and it is great for updating charts and status UIs on the fly without hacking extra ports, server daemons and whatnot.
265 comments
[ 2.0 ms ] story [ 282 ms ] threadThat is wrong. Edit: Actually it seems correct (a javascript problem, not SSE problem) but it's a non-problem if you use a parameter for that data instead and read it on the server.
However you are correct that if you’re not using JavaScript and connecting directly to the SSE endpoint via something else besides a browser client, nothing is preventing anyone from using custom headers.
[1] https://developer.mozilla.org/en-US/docs/Web/API/EventSource...
In my example I use this code:
Is that true? The web never cease to amaze.
I don't see why WebSockets should benefit from HTTP. Besides the handshake to setup the bidirectional channel, they're a separate protocol. I'll agree that servers should think twice about using them: they necessitate a lack of statelessness & HTTP has plenty of benefits for most web usecases
Still, this is a good article. SSE looks interesting. I host an online card game openEtG, which is far enough from real time that SSE could potentially be a way to reduce having a connection to every user on the site
1) More complex and binary so you cannot debug them as easily, specially on live and specially if you use HTTPS.
2) The implementations don't parallelize the processing, with Comet-Stream + SSE you just need to find a application server that has concurrency and you are set to scale on the entire machines cores.
3) WebSockets still have more problems with Firewalls.
https://github.com/tinspin/rupy/wiki/Comet-Stream
Old page, search for "event-stream"... Comet-stream is a collection of techniques of which SSE is one.
My experience is that SSE goes through anti-viruses better!
Hmm, another commenter says the opposite:
https://news.ycombinator.com/item?id=30313692
rupy is a minimalist, from scratch, HTTP app-server that uses non-blocking IO so it can scale comet-stream (SSE or not) which is much better than WebSockets: https://news.ycombinator.com/item?id=30313403
I will never make projects that you just download and double click to run.
I want my users to understand how it works more than I want them to use it!
Or maybe I'm just lazy... :S
The way I solve it is to send "noop" messages at regular intervals so that the socket write will return -1 and then I know something is off and reconnect.
One example where i found it to be not the perfect solution was with a web turn-based game.
The SSE was perfect to update gamestate to all clients, but to have great latency from the players point of view whenever the player had to do something, it was via a normal ajax-http call.
Eventually I had to switch to uglier websockets and keep connection open.
Http-keep-alive was that reliable.
With the downsides of HTTP/1.1 being used with SSE, websockets actually made a lot of sense, but in many ways they were a kludge that was only needed until HTTP/2 came along. As you said, communicating back to the server in response to SSE wasn’t great with HTTP/1.1. That’s before mentioning the limited number of TCP connections that a browser will allow for any site, so you couldn’t use SSE on too many tabs without running out of connections altogether, breaking things.
No new connection and no low-level connection (TCP, TLS) handshakes, but the server still has to parse and validate the http headers, route the request, and you'd probably still have to authenticate each request somehow (some auth cookie probably), which actually may start using a non-trivial amount of compute when you have tons of client->server messages per client and tons of clients.
SSE streams are multiplexed into a HTTP2 stream, so they can suffer from congestion issues caused by unrelated requests.
In contrast, HTTP2 does not support websockets, so each websocket connection always has its own TCP connection. Wasteful, but ensures that no head-of-line blocking can occur.
So it might be that switching from SSE to websockets gave better latency behaviour, even though it had nothing to do with the actual technologies.
Of course, this issue should be solved anyway with HTTP3.
That’s not how head-of-line blocking works. Just having a single stream doesn’t guarantee no blocking. It’s not really about unrelated requests getting in the way and sucking up bandwidth (that’s a separate issue, and arguably applies regardless of how many TCP connections you have), head-of-line blocking is about how TCP handles retransmission of lost packets. Websocket suffers from head-of-line blocking too, which is a reason that WebTransport is being developed.
Certainly, if you have other requests in flight, you could have head-of-line blocking because of a packet that was dropped in a response stream that isn’t related to your SSE stream, but this only applies if there’s packet loss, and the packets that were lost could just as easily be SSE’s or websocket’s.
I agree that HTTP/3 should solve the issue of head-of-line blocking being caused by packets lost from an unrelated stream, but it doesn’t prevent it from occurring entirely.
My understanding (which could be wrong) is that WebTransport is supposed to offer the ability to send and receive datagrams with closer to UDP-level guarantees, allowing the application to continue receiving packets even when some go missing, and then the application can decide how to handle those missing packets, such as asking for retransmission. Getting an incomplete stream at the application level is what it takes to entirely avoid head-of-line blocking.
As alluded to earlier, there is zero head-of-line blocking if there is no packet loss. Outside of congested networks or the lossy fringes of cell service, I really wonder how much of an issue this is. I’m skeptical that it adds any latency for SSE vs websocket in the average benchmark or use case. The latency should be nearly identical. Your comment seems predicated on it definitely being worse, but based on what numbers? I admit it’s been a couple of years since I measured this myself, but I came away with the conclusion that websockets are massively overrated. There are definitely a handful of use cases for websockets, but… it shouldn’t be the tool everyone reaches for.
HTTP/3 is really meant to be an improvement for a small percentage of connections, which is a huge number of people at the scale that Google operates at. I don’t think there are really any big downsides to HTTP/3, so I look forward to seeing it mature, become more common, and become easier to find production grade libraries for.
That was what I meant. Yes, head-of-line blocking can occur everywhere there is TCP, but with HTTP2, the impact is larger due to the (otherwise very reasonable) multiplexing: When a HTTP2 packet is lost, this will stall all requests that are multiplexed into this connection, whereas with websocket, it will only stall the websocket connection itself.
Very interesting ! I honestly didn't know that, or even think about it like that ! #EveryDayYouLearn :)
Can you recommend some resources for learning SSE in depth?
It's not the most well documented but it's the smallest implementation while still being one of the most performant so you can learn more than just SSE.
Thanks!
They'll try to read the entire stream to completion and will hang forever.
1) Push a large amount of data on the pull (the comet-stream SSE never ending request) response to trigger the middle thing to flush the data.
2) Using SSE instead of just Comet-Stream since they will see the header and realize this is going to be real-time data.
We had 99.6% succes rate on the connection from 350.000 players from all over the world (even satellite connections in the Pacific and modems in Siberia) which is a world record for any service.
350.000 was the total number of players during 6 years.
https://store.steampowered.com/app/486310/Meadow/
We have had a total of 350.000 players over 6 years and the backend out-scales all other multiplayer servers that exist and it's open source:
https://github.com/tinspin/fuse
You don't need HTTP/2 to make SSE work well. Actually the HTTP/2 TCP head-of-line issue and all the workarounds for that probably make it harder to scale without technical debt.
That said if you, like SSE on HTTP/1.1; use 2 sockets per client (breaking the RFC, one for upstream and one for downstream) you are golden but then why use HTTP/2 in the first place?
HTTP/2 creates more problems than solutions and so does HTTP/3 unfortunately until their protocol fossilizes which is the real feature of a protocol, to become stable so everyone can rely on things working.
In that sense HTTP/1.1 is THE protocol of human civilization until the end of times; together with SMTP (the oldest protocol of the bunch) and DNS (which is centralized and should be replaced btw).
Really people should try and build great things on the protocols we have instead of always trying to re-discover the wheel, note: NOT the same as re-inventing the wheel: http://move.rupy.se/file/wheel.jpg
Take Snap. Say they reduced time to view a snap by 10ms. After 100 snaps that’s an additional 1 second of engagement. This could equate to an additional ad impression every week per user. Which is many millions of additional revenue.
Please elaborate.
"QUIC is a new always-encrypted general-purpose transport protocol being standardized at the IETF designed for multiplexing multiple streams of data on a single connection. HTTP/3 runs over QUIC and roughly replaces HTTP/2 over TLS and TCP. QUIC combines the cryptographic and transport handshakes in a way to allow connecting to a new server in a single round trip and to allow establishing a resumed connection in zero round trips, with the client sending encrypted application data in its first flight. QUIC uses TLS 1.3 as the basis for its cryptographic handshake.
This talk will provide an overview of what the QUIC protocol does and how it works, and then will dive deep into some of the technical details. The deep dive will focus on security-related aspects of the protocol, including how QUIC combines the transport and cryptographic handshakes, and how resumption, including zero-round-trip resumption works. This will also cover how QUIC’s notion of a connection differs from the 5-tuple sometimes used to identify connections, and what QUIC looks like on the wire.
In addition to covering details of how QUIC works, this talk will also address implementation and deployment considerations. This will include how a load balancer can be used with cooperating servers to route connections to a fleet of servers while still maintaining necessary privacy and security properties. It will also look back at some of the issues with HTTP/2 and discuss which ones may need to be addressed in QUIC implementations as well or are solved by the design of QUIC and HTTP/3."
But even if the definition were different, http+tls would also be e2e encrypted (if used in conjunction which it pretty much always is).
I appreciate Quic but from a security perspective I don't see how it's different to what we've had for at least a decade.
It's amazing that we've been able to adapt the protocol in a backwards-compatible fashion for over 30 years, but QUIC addresses problems with TCP in ways that could not be done in a backwards-compatible fashion. Personally I wish the protocol were simpler, but I lack the expertise to say what should be removed.
So much nonsense in a single paragraph, amazing.
If anything DNS is less centralized then http and SMTP. Its a surprisingly complicated system for what it does because of all the caching etc, but calling it more centralized then http is just is just ignorant to a silly degree
That's said, it's very cool. Do you have a development blog for Meadow?
No, no dev log but I'll tell you some things that where incredible during that project:
- I started the fuse project 4 months before I set foot in the Meadow project office (we had like 3 meetings during those 4 months just to touch base on the vision)! This is a VERY good way of making things smooth, you need to give tech/backend/foundation people a head start of atleast 6 months in ANY project.
- We spent ONLY 6 weeks (!!!) implementing the entire games multiplayer features because I was 100% ready for the job after 4 months. Not a single hickup...
- Then for 7 months they finished the game client without me and released without ANY problems (I came back to the office that week and that's when I solved the anti-virus/proxy cacheing/buffering problem!).
I think Meadow is the only MMO in history so far to have ZERO breaking bugs on release (we just had one UTF-8 client bug that we patched after 15 minutes and nobody noticed except the poor person that put a strange character in their name).
Not MIT then. The beauty of MIT is that there is no stuff.
Here it's clear, you can either use the code without money involved and then you have MIT (+ show logo and some example code is still mine).
If you want money then you have to share some of it.
But really open-source (as in free) is the misnomer here, it should be called free open-source, or FOSS as some correctly name it.
FOSS or F/OSS is a combination of Free (as defined by the FSF) and Open Source (as defined by the OSI) (the last S is Software), which recognizes that the two terms, while they come from groups with different ideological motivations, refer to approximately the same substantive licensing features and almost without exception the same set of licenses.
We all need to get out of the current legal/monetary system soon enough.
Since when was "open source" generic? These obnoxious idealists you're complaining about are the people who invented the term in the first place.
The bare reality is that it's just a commercial license.
Your license is not that. You have extra conditions that add complexity. I can no longer go "oh like MIT" and immediately use it for any purpose, because you require extras especially if I were to make money. That seems completely against the spirit of the simplicity of the MIT license which says you can do whatever you like, commercial or otherwise, as long as the copyright and license are included.
I think you should make your own license that includes the text of the MIT license, except removing the irrelevant parts (ie the commercial aspects include a caveat about requiring payment). You can still have a separate line of text explaining that the license is like the MIT license but with XYZ changes (basically the text you have now). But the license is not the MIT license and you should therefore have a separate license text that spells it out exactly. Not "its this, except scratch half of it because these additional terms override a good chunk of it".
I'm also sad that nobody has solved this license problem yet, there is obviously a need for it. Sometimes time solves all problems though, so I probably just have to wait a while and somebody makes exactly the right license.
But I'm going to allocate some time if somebody who is willing to pay approaches me with the same concerns (it's actually why I switched to MIT in the first place, Unreal does not allow you to use client plugins that are LGPL)...
Small steps, we'll get there!
What? To keep your existing license you copy the text of the MIT license, add the statement about requiring a logo and remove the parts about being able to use the code commercially, and add an extra paragraph that has the text you already have: to use commercially you have to sponsor. It’s not about changing your terms, it’s about being clear about what license applies. Hybrid with MIT and other implies that the MIT license somehow applies yet it does not since your “other” invalidates a chunk of what the MIT license allows. Just removing those bits and not calling it MIT is enough.
If that significantly cuts into your time to do other stuff then I don’t know what to say.
> if somebody who is willing to pay approaches me with the same concerns
I’m not concerned about the license per se. It wouldn’t stop me from paying if I wanted to use your software. It’s just that to everyone looking, before even evaluating it, you’re sending a dishonest message, that somehow the MIT license applies when it clearly does not.
I would create a license.txt file that contains a copy of the MIT license text with the commercial use phrasing removed, the need for displaying logo added a second paragraph before the warranty disclaimer stating that you may use the software commercially so long as you sponsor (same text you already have). Then I would link it from the readme with an explanation: proprietary license that is similar to the MIT license except with the conditions of logo and for commercial use requiring sponsorship (existing text more or less). Clear, simple and should take you no more than ten minutes to fix.
My objection is that you are claiming it’s under MIT license and using the MIT licenses name recognition, while applying changes that very clearly make it not MIT license at all.
"Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:"
Became
"Permission is hereby granted, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software, including the rights to copy, modify, merge, publish and/or distribute the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:"
And then I list the stuff...
1) You have to show the logo on startup.
2) You have to sponsor the fuse tier on gumroad while you are using the Software, or any derived Software, commercially:
https://tinspin.gumroad.com/l/xwluh
3) The .html and graphics are proprietary examples except the javascript in play.html
4) The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
it feels completely meaningless to put it that way... laws are really the most superficial waste of time, it only took 5 minutes to edit but it's a lifetime of trouble!
But thanks I guess, if it works... but you only know that later... possibly eons later!
> I didn't know how small the MIT license was!!!
This is kind of a problem, before you were saying its like the MIT license but if you didn't know how small it was, you couldn't have read it, so...
Anyway, no point in beating a dead horse, you have corrected the issue I had, so thank you!
> laws are really the most superficial waste of time
Until you need them, at least.
In any case, good luck with your project. It does technically look very interesting.
Can you explain what you mean here? What was your peak active user count, what was peak per server instance, and why you think that beats anything else?
Under Performance. Per watt the fuse/rupy platform completely crushes all competition for real-time action MMOs because of 2 reasons:
- Event driven protocol design, averages at about 4 messages/player/second (means you cannot do spraying or headshots f.ex. which is another feature in my game design opinion).
- Java's memory model with atomic concurrency parallelism over shared memory which needs a VM and GC to work (C++ copied that memory model in C++11, but it failed completely because they lack both VM and GC, but that model is still to this day the one C++ uses), you can read more about this here: https://github.com/tinspin/rupy/wiki
These keep the internal latency of the server below maybe 100 microseconds at saturation, which no C++ server can handle even remotely, unless they copy Java's memory model and add a VM + GC so that all cores can work on the same memory at the same time without locking!
You can argue those points are bad arguments, but if you look at performance per watt with some consideration for developer friendlyness, I'm pretty sure in 100 years we will still be coding minimalist JavaSE (or some copy without Oracle) on the server and vanilla C (compiled with C++ compiler gcc/cl.exe) on the client to avoid cache misses.
Energy is everything!
Do you have a link that explains this bit?
I don't understand what particular piece of magic makes shared-memory concurrency under a VM+GC faster than a CAS implementation.
[1] I'm assuming a shared-memory threaded model of concurrency, not a shared-nothing message passing model of concurrency.
Me neither, but I know it does in practice.
My intuition tells me the VM provides a layer decoupled from the hardware memory model so that there is less "friction" and the GC is required to reclaim shared memory that C++ would need to "stop the world" to reclaim anyhow! (all concurrent C++ objects leaks memory, see TBB concurrent_hash_map f.ex.) That means the code executes slower BUT the atomics can work better.
As I said; for 5 years I have been searching for answers from EVERYONE on the planet and nobody can answer. My guess is that this is so complicated, only a handfull can even begin to grook it, so nobody wants to explain it because it creates alot of wasted time.
The usual reaction is: Java is written in C, so how can Java be faster than C? Well I don't know how but I know it's true because I use it!
So my answer today is: Java is faster than C if you want to share memory between threads directly efficiently because you need a VM with GC to make the Java memory model (which everyone has copied so I guess it must be good?) work!
Here is someone who knows his concurrency and made C++ maps that might be better than TBB btw: https://github.com/preshing/junction
But no guarantees... you never get those with C/C++, I stopped downloading C/C++ code from the internet unless it has 100+ proved users! So stb/ttf and kuba/zip are my only dependencies.
https://en.wikipedia.org/wiki/Compare-and-swap
> My intuition tells me the VM provides a layer decoupled from the hardware memory model so that there is less "friction" and the GC is required to reclaim shared memory that C++ would need to "stop the world" to reclaim anyhow! (all concurrent C++ objects leaks memory, see TBB concurrent_hash_map f.ex.) That means the code executes slower BUT the atomics can work better.
I dunno about the GC bits; after all object pools are a thing in C++ so you have a consistent place (getting a new object) where reclamation of unused objects can be performed.
I think it might be down to mutex locking. In a native program, a failure to acquire the mutex causes a context-switch by performing a syscall (OS steps in, flushes registers, cache, everything, and runs some other thread).
In a VM language I would expect that a failure to acquire a mutex can be profiled by the VM with simple heuristics (Only one thread waiting for a mutex? Spin on the mutex until its released. More than five threads in the wait queue? Run some other thread).
My license is messy but if you search for "license" on the main github page you'll eventually find MIT + some ugly modifications I made.
https://github.com/open-wa/wa-automate-nodejs
There should be some sort of support group for those of us trying to monetize (sans donations) our open source projects!
We probably need a new license though because piggybacking on MIT (or any other license) like I try to do is rubbing people the wrong way.
But law and money are my least favourite passtimes, so I'm going to let somebody else do it first unless somebody is willing to force this change by buying a license and asking for a better license text.
Your source-available projects. Nothing wrong with licensing your work that way (in the sense that you can make that choice, not in the sense that I think its a good idea) but please don't muddle the term "open source".
[0]: https://www.eclipse.org/paho/index.php?page=clients/js/index...
Essentially just new EventSource(), text/event-stream header, and keep conn open. Zero dependencies in browser and nodejs. Needs no separate auth.
The one thing I wish they supported was a binary event data type (mixed in with text events), effectively being able to send in my case image data as an event. The only way to do it currently is as a Base64 string.
Ultimately what I did was run an SSE request and long polling image request in parallel, but that wasn’t ideal as I had to coordinate that on the backend.
This lets us then stream the image as a steaming http response from the front end, potentially before the jpg has finished being generated on the backend.
So from the SSE we know the url the image is going to be at before it’s ready, and effectively long poll with a ‘new Image()’.
$ ls -l PXL_20210926_231226615.*
-rw-rw-r-- 1 derek derek 8322217 Feb 12 09:20 PXL_20210926_231226615.base64
-rw-rw-r-- 1 derek derek 6296892 Feb 12 09:21 PXL_20210926_231226615.base64.gz
-rw-rw-r-- 1 derek derek 6160600 Oct 3 15:31 PXL_20210926_231226615.jpg
As an aside, Django with Gevent/Gunicorn does SSE well from our experience.
My experience, now a bit dated, is that long polling is the only thing that will work 100% of the time.
It's possible to detect that, and fall back to long polling. Send an event immediately after opening a new connection, and see if it arrives at the client within a short timeout. If it doesn't, make your server close the connection after every message sent (connection close will make AV let the response through). The client will reconnect automatically.
Or run:
Also ease of use doesn’t really convince me. It’s like 5 lines of code with socket.io to have working websockets, without all the downsides of sse.
You have to send "Content-Type: text/event-stream" just to make them work.
And you keep the connection alive by sending "Connection: keep-alive" as well.
I've never had any issues using SSEs.
That sounds like a self-inflicted problem. Even if you’re using tokens, why not store them in a session cookie marked with SameSite=strict, httpOnly, and secure? Seems like it would make everything simpler, unless you’re trying to build some kind of cross-site widget, I guess.
You simply get stuff like auto-reconnect and graceful failover to long polling for free when using socket.io
Neither of those being built into a third party websocket library are actually advantages for websocket… they just speak to the additional complexity of websocket. Plus, long polling as a fallback mechanism can only be possible with server side support for both long polling and websocket. Might as well just use SSE at that point.
long polling shouldn’t be needed anymore, and auto reconnect is trivial to implement.
Read my comment below about that.
It's just random that your ISP like WebSockets more than long HTTP responses, and it can change in a heartbeat and for most people it will be different. As I said before 99,6% successful networking is an unheard of number for real-time multiplayer games.
I only care about that number, until you proove with hard stats and 350.000 real users from everywhere on the planet that WebSocket has 99,7% success rate, I'm not even going to flinch.
Server-sent events appears to me to just be chunked transfer encoding [0], with the data structured in a particular way (at least from the perspective of the server) in this reference implementation (tl,dr it's a stream):
https://gist.github.com/jareware/aae9748a1873ef8a91e5#file-s...
[0]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding
Which seems to be what you need to send 'headers' after a chunked response.
You can kludge it with fetch(...) and the body stream
1. <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>
With current day APIs, including streaming response bodies in the fetch API, SSE would probably not have been standardized as a separate browser API.
You can also implement websockets in 5 lines (less, really 1-3 for a basic implementation) without socket.ii. Why are you still using it?
There are some hacks to work around it though.
(There's one person in this thread who is just ridiculously opposed to HTTP/2, but... HTTP/2 has serious benefits. It wasn't developed in a vacuum by people who had no idea what they were doing, and it wasn't developed aimlessly or without real world testing. It is used by pretty much all major websites, and they absolutely wouldn't use it if HTTP/1.1 was better... those major websites exist to serve their customers, not to conspiratorially push an agenda of broken technologies that make the customer experience worse.)
True but the limit for websockets these days is in the hundreds, as opposed to 6 for regular HTTP requests.
It appears to be 30 per domain, not “hundreds”, at least as of the time this answer was written. I didn’t see anything more recent that contradicted this.
In practice, this is unlikely to be problematic unless you’re using multiple websockets per page, but the limit of 6 TCP connections is even less likely to be a problem if you’re using HTTP/2, since those will be shared across tabs, which isn’t the case for the dedicated connection used for each websocket.
https://chromium.googlesource.com/chromium/src/net/+/259a070...
Agree that it should be much less of a problem with HTTP/2 than HTTP/1.1.
The SSE connection limit is a nasty surprise once you run into it, it should have been mentioned.
It does not apply to HTTP/2, as previously noted.
> Http2 is easy to set up, so are websockets, yet debugging the multiplexed http2 stream is is not that simple anymore.
I have literally never heard of anyone I personally know having to debug HTTP/2 on the wire. Unless you believe there are frequently bugs in the HTTP/2 implementation in your browser or the library you use, this just not a real concern. HTTP/2 has been around long enough that this is definitely not a concern of mine. I would be more worried about bugs with HTTP/3, since it is so new.
Websockets are also not especially easy to set up… they don’t work with normal HTTP servers and proxies, so you have to set up other infrastructure.
It also seems that compression for websockets is supported in all major browsers.
The article's argument seems to be that ws adds complexity, but this is present in pretty much all web servers already, the user needs not to deal with it. (HTTP2, too, requires the same type of complexity for that matter)
It's a beautifully simple & elegant lightweight push events option that works over standard HTTP, the main gotcha for maintaining long-lived connections is that server/clients should implement their own heartbeat to be able to detect & auto reconnect failed connections which was the only reliable way we've found to detect & resolve broken connections.
That sounds like a total nightmare!
> SSE is subject to limitation with regards to the maximum number of open connections. This can be especially painful when opening various tabs as the limit is per browser and set to a very low number (6).
https://ably.com/blog/websockets-vs-sse
SharedWorker could be one way to solve this, but lack of Safari support is a blocker, as usual. https://developer.mozilla.org/en-US/docs/Web/API/SharedWorke...
also, for websockets, there are various libs that handle auto-reconnnects
https://github.com/github/stable-socket
https://github.com/joewalnes/reconnecting-websocket
https://dev.to/jeroendk/how-to-implement-a-random-exponentia...
Well it's a non-problem, if you need more bandwith than one socket in each direction can provide you have much bigger problems than the connection limit; which you can just ignore.
in most cases this is not a concern, but in some cases it is.
Or make your own tab system inside one browser tab.
I can see why that is a problem for some.
If you’re still using HTTP/1.1, then yes, this would be a problem.
maybe it was inability to do broadcast to multiple open sse sockets from nodejs.
i should revisit.
https://medium.com/blogging-greymatter-io/server-sent-events...
That's (long) polling, not SSE. The only overhead for SSE are the "data", "event", etc pseudo header names and possibly some chunked-encoding markers. Both are tiny though.
What I mean by that is client sends request, server responds in up to 2 minutes with result or a try again flag. Either way client resends request and then uses response data if provided.
Comet-stream and SSE will save you alot of bandwidth and CPU!!!
https://github.com/tinspin/fuse/blob/master/res/play.html#L1...
The XHR ready state 3 was wrongly implemented in IE7, they fixed it in IE8.
1. https://jmap.io/spec-core.html#event-source
You can't say that and not say more about it, haha. Please expand on this?
Also, I'm a Fastmail customer and appreciate the nimble UI, thanks!
Before that... yeah, the Firefox dev tools were not very helpful for SSE.