Question

I'm working on DB design tool (python, gevent-socket.io). In these tool multiple users can discuss one DB model, receiving changes in runtime. To support this feature, I'm using socket.io. I'd like to extend number of servers that handle socket.io connection easily. The simplest way to do it is to set up nginx to choose server basing of model ID.

I'd like module approach, where model ID is divided by number of servers. So if I have 3 nodes, model 1 will be handled on first, 2 - on second, 3 - on third, 4 - on first again etc.

My request for model loading looks like /models/, so no problem here - argument can be parsed to find server to handle it. But after model page is loaded, JS tries to establish connection:

var socket = io.connect('/models', {
            'reconnection limit': 4000
        });

It accesses default endpoint, so server receives following requests:

http://example.com/socket.io/1/xhr-pooling/111111?=1111111

To handle it, I create application this way:

SocketIOServer((app.config['HOST'], app.config['PORT']), app, resource='socket.io', transports=transports).serve_forever()

and then

@bp.route('/<path:remaining>')
def socketio(remaining):
    app = current_app._get_current_object()
    try:
        # Hack: set app instead of request to make it available in the namespace.
        socketio_manage(request.environ, {'/models': ModelsNamespace}, app)
    except:
        app.logger.error("Exception while handling socket.io connection", exc_info=True)
    return Response()

I'd like to change it to

http://example.com/socket.io/<model_id>/1/xhr-pooling/111111?=1111111

to be able to choose right server in ngnix. How to do it?

UPDATE

I also like to check user permissions when it tries to establish connection. I'd like to do it in socketio(remaining) method, but, again, I need to know what model he is trying to access.

UPDATE 2

I implemented permission validator, taking model_id from HTTP_REFERER. Seems, it's only part of request that contains identifier of the model (example of values: http://example.com/models/1/).

Was it helpful?

Solution

The first idea - is to tell client side available servers for current time. Furthermore you can generate server list for client side by priority, just put them in javascript generated array by order. This answer means that your servers can answer on any models, you can control server loading by changing servers ordering in generated list for new clients.

I think this is more flexible way. But if you want - you can parse query string in nginx and route request on any underlying server - just have a table for "model id-server port" relations

Upd: Just thinking about your task. And find one another solution. When you generate client web page you can inline servers count in js somewhere. Then, when you requesting model updates, just use another parameter founded as

serverId = modelId%ServersCount;

that will be server identificator for routing in nginx. Then in nginx config you can use simple parsing query string, and routing request to server you can find by serverId parameter.

in "metalanguage" it will be

  1. get parameter serverId to var $servPortSuffix
  2. route request to localhost:80$servPortSuffix

or another routing idea.

You can add additional GET parameters to socket.io via

io.connect(url, {query: "foo=bar"})
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top