pando.py icon indicating copy to clipboard operation
pando.py copied to clipboard

(Re-)Implement websocket/socket.io simplates

Open chadwhitacre opened this issue 12 years ago • 16 comments

Right now we just have XHRPolling

chadwhitacre avatar Jun 24 '13 14:06 chadwhitacre

WSGI can't support socket.io/websockets.

So to do this we have to:

  1. make the aspen server rock solid as it's going to be the only way to support websockets
  2. either give up WSGI support, or have a switch to disable websockets (automatically turned on if the request comes in via the WSGI API)

pjz avatar Aug 10 '13 03:08 pjz

Aspen's rock-solidity depends greatly on the networking library used. We support nine, which doesn't lend towards rock-solidity. One strategy, therefore, would be to pick one networking engine, probably gevent or diesel.

chadwhitacre avatar Aug 10 '13 05:08 chadwhitacre

@pjz How does websockets relate to fastcgi?

chadwhitacre avatar Aug 10 '13 14:08 chadwhitacre

It doesn't. FastCGI and WSGI both allow the webserver to break up multiple requests from a single connection across multiple backend FastCGI or WSGI processes; websockets seems to require that it get full control of the actual connection socket. Thus, I think they're fundamentally incompatible. See also http://stackoverflow.com/questions/13137449/combining-websockets-and-wsgi-in-a-python-app

pjz avatar Aug 12 '13 14:08 pjz

Lots of conversation on this at @pjz's. Let's spike out using:

http://www.gelens.org/code/gevent-websocket/

Can that support what we need for thread-pooled WSGI as well as the WebSocket upgrade when needed?

chadwhitacre avatar Sep 21 '13 17:09 chadwhitacre

WebSockets are important because they're the forerunner of HTTP 2.0, and that's a puck we want to skate ahead of.

chadwhitacre avatar Sep 23 '13 15:09 chadwhitacre

FWIW Armin Ronacher wrote about adding realtime support to web applications last year in a way that allows you to keep your webserver stateless and using the WSGI protocol. Depending on what you're trying to solve, specifically rewriting for websockets may be the goal, or perhaps it's more general: allow realtime websites.

Basically, you have a public-facing server that handles the persistent connections and adds them to Redis. Your webserver instances and background workers listen for this and process them accordingly. The results are pushed back onto Redis, and the public-facing server can either generate an HTTP response like normal, or push the result to all open connections on a particular channel.

This keeps your website code the same: process a request and generate a response. (Your background workers can still generate broadcasts without a request triggering it, if you need time-based broadcasts instead of request-based.) So it's still WSGI and still stateless. As a bonus, you can upgrade your website without actually closing any connections. Just throwing this out there in case "realtime web" is the underlying reason for websockets. Either way, it's a good read.

joeyespo avatar Sep 24 '13 16:09 joeyespo

Thanks @joeyespo. Sounds like he is recommending two servers?

  • a realtime server that maintains the standing connections and subscribes to redis. The messages that come from redis are then sent to the connected clients that want them. If you want bidirectional communication you can also accept messages from the clients and put them on the queue for Flask to pick up.
  • a regular webserver for exposing your WSGI app to the web. This could be nginx, Apache or whatever floats your boat.

chadwhitacre avatar Sep 24 '13 16:09 chadwhitacre

I think he means "server" as defined by WSGI, the code that provides environment information and a callback to the application. You could use two ports or subdomains instead of two machines.

My interpretation is, all websocket connections are handled with the realtime "server" so it can generate requests from incoming data, let your WSGI application handle it, and then broadcast the responses. This separates the concerns so you can continue to write "applications" without gevent, etc.

I think you could do this within a single Aspen process. Have a "realtime engine" that does just this so you can continue to write Aspen websites the way you have. You'll break connections on upgrades this way. Though if you expose the engine in the CLI, you could run the engine and your Aspen application in separate processes or even separate machines, you'll get that feature back when it becomes important.

joeyespo avatar Sep 24 '13 17:09 joeyespo

You could use two ports or subdomains instead of two machines.

Right. I was really hoping we could find a way to avoid two ports/subdomains.

chadwhitacre avatar Sep 24 '13 17:09 chadwhitacre

Well you could use nginx URL-based routing. Or if you want it all in one process, have Aspen route the websocket connection requests to the realtime engine, and web requests sent directly, bypassing the pubsub mechanism.

The realtime engine can still be its own thing, within Aspen. And if it's exposed, you have the choice of using a dedicated machine, scaling up the number of WSGI instances and background workers as-needed and allowing server updates without losing connections. For small projects, these probably aren't a concern yet, so having the code in Aspen is useful.

joeyespo avatar Sep 24 '13 21:09 joeyespo

P.S. Websockets are in labs at Heroku now:

https://devcenter.heroku.com/articles/heroku-labs-websockets

chadwhitacre avatar Oct 14 '13 20:10 chadwhitacre

Here's a slide deck on "Making HTTP realtime with HTTP 2.0":

https://docs.google.com/presentation/d/1eqae3OBCxwWswOsaWMAWRpqnmrVVrAfPQclfSqPkXrA/present#slide=id.p19

chadwhitacre avatar Oct 21 '13 13:10 chadwhitacre

@whit537 don't know why none mention but: gevent-socketio

I was using it with Django and they worked really fine :)

galuszkak avatar Jan 06 '14 22:01 galuszkak

Okay, #324 just dropped socket simplates as part of ripping out network_engines. This is an issue to remind us that someday we want that functionality back.

pjz avatar May 06 '14 20:05 pjz

...there's a new solution: ASGI which has a good summary in the intro. I think this will allow @chadwhitacre 's original vision of allowing a simplate to be either a page or a websocket.

pjz avatar Sep 21 '18 15:09 pjz