Search code examples
python-2.7restnginxuwsgifalconframework

Erratic behaviour of variables in Falcon


Situation

I have one computer connected to multiple instruments. On this computer, there's an nginx server that serves a Falcon WSGI application using uWSGI. The application is thought so that if one user requires access to an instrument, this becomes unavailable to others. I achieve this by the following piece of (stripped-down version of my) code:

import json
import falcon

class Lab(object):
    def __init__(self):
        self.available_instruments = ["money_maker", "unicornifier"]  # Not actual instruments
        self.connected_instruments = []
    def on_get(self, request, response):
        response.status = falcon.HTTP_OK
        response.content_type = "application/json"
        response.body = json.dumps({
            "connected": self.connected_instruments,
            "available": self.available_instruments
        })
    def on_post(self, request, response):
        json_body = json.loads(request.body)
        instrument = json_body['connect']
        if instrument in self.connected_instruments:
            raise falcon.HTTPBadRequest('Busy')
        elif instrument not in self.available_instruments:
            raise falcon.HTTPBadRequest('No such instrument')
        self.connected_instruments.append(instrument)
        response.status = falcon.HTTP_OK
        response.content_type = "application/json"
        response.body = json.dumps({
            "connected": self.connected_instruments,
            "available": self.available_instruments
        })

application = falcon.API()
l = Lab()
application.add_route('/', lab)

And the request body

{
    "connect": "money_maker"
}

The problem

When I "connect" an instrument, the immediate answer shows that it is connected. But successive GET requests don't give the expected answer. I get

{
    "connected": [],
    "available": ["money_maker", "unicornifier"]
}

But this does not happen if I execute the above code on a local uWSGI instance, for testing purposes. Is there any nginx-uWSGI interaction that I'm not aware of? Any amount of help is appreciated.

For the sake of completeness, here follow the nginx.conf and the api.ini file called by uWSGI.

nginx/sites-available/api

#nginx config file for uWSGI requests routing
server {
    listen 80;
    server_name example.com;
    location /api {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/api.sock;
    }
}

api.ini

[uwsgi]

master = true
processes = 5

socket = /tmp/%n.sock
chmod-socket = 666
uid = apidev
gid = www-data

chdir = %d../%n
pythonpath = %d../%n

module = %n

vacuum = true

Solution

  • self.connected_instruments.append(instrument)
    

    just stores the posted data in memory! ie, in the memory space of one process... but when you run 5 uwsgi processes behind nginx then you have a very high chance of posting the data to one process and then being served by another process who does not have that data.

    You must use a database or something that all processes can share to save and retrieve data.