Web clients, browsers, and backends
Sometimes, the concept of 'state' is useful, especially when navigating a website. Unfortunately, HTTP is stateless. So, what do we do about that? How do we track the browser? Oh, right, cookies. Except, that only happens when the browser sends a request. We can't check if they're still there 5 hours later. And they sure won't tell the server if/when they leave.
State? HTTP?
What am I even on about? - is a valid question. Unless you're in the niche of hand-coded web development, you probably don't even think about these things. I've talked about 'state' previously, try reading that if you have no idea what I'm on about. What's HTTP? If you're old enough to remember the good ol' days of the web, you can recall countless times of meticulously typing out h t t p : / / w w w
and so on. It's the communication protocol that makes the whole internet work.
Just gimme an example
You make a search, and tap/click onto a website. When you do, your browser sends a request to the webserver that runs that particular website. The webserver then responds with the actual website content, which is processed and displayed by your browser for you. The browser (client) always makes requests to the website (server), which can only ever send a single response. Overall, the server doesn't know one client's request from another, unless you do something with cookies to try and match up the client behind it, to the request itself.
Enter WebSocket
WebSockets are a fantastically cool JavaScript thing. They're super simple and easy, and let you fire data back and forth between a server and a client at will. The big deal with them is that they're a separate connection 'event' to the regular traffic, and also a separate disconnect event. Guaranteed, too. All done, right? Just slap a WebSocket connection on and you're all good? Yeah nah, it lives in JavaScript, which lives and dies... with the page. Not the client, not the overall "session" between the client and server.
A solution
Luckily, not all JavaScript lives and dies with the page. There's also this other neat thing, called Workers. The first type of worker, the Dedicated Worker, let's you run stuff in the background, away from the page. It's ideal... until you navigate somewhere else, or refresh the page, or basically do anything. They actually still live and die with the page.
Shared Workers
To complement Dedicated Workers, there exists Shared Workers. They live and die based on when they're needed. If you have two tabs open on the same website, using the same shared worker, then it is the same worker. Literally, you can identically share it (and its data!) between all the pages, in the client's browser.
What does all this mean?
It means magic can happen. The client/user makes a regular request to the website/server, get's a regular response - with a shared worker. The client then starts up the shared worker, which runs a WebSocket connection back the server. You can do whatever, the shared worker runs in the background, which allows it to maintain a constant connection, and when you're done and you close your browser, the server gets notified. It's a brilliantly simple and effective system.
The catch
Someone else noticed it was cool, too (in 2014!). But, they also noticed a problem: it don't work like that. Unless you literally are sharing the shared worker (i.e. 2+ tabs with the same page/website), Chrome runs it as a Dedicated Worker. Thus, it lives and dies with the page.
The solution?
So, they did something about it. They submitted a request to W3C (World Wide Web Consortium), to amend the official specification to explicitly allow for this behaviour (persistent WebSocket in a single-page Shared Worker). And they actually got somewhere. It took most of the year, but it went from "that's an interesting idea" to verbatim part of the spec. You can still see it for yourself.
Where does that leave us today?
Chrome... still doesn't support it. That therefore goes for it's derivatives, too. However, Firefox does.
What's the actual solution?
Cookies, and Shared Workers, and WebSockets. If you put them all together, you can get a reasonable solution.
The process
- When a new client connects, set a session cookie with a unique identifier
- Track the WebSocket connecting and disconnecting with normal navigation, associating with the client via the cookie
- When a new client connects again, check through all the other WebSockets, to see if any are disconnected
- If so, free up server-side resources, and forget about them
The whole thing is pretty much irrelevant for Firefox users, and works seamlessly with Chrome. And of course, it remains pretty simple to actually implement.