Search code examples
pythoncherrypy

How does request isolation work in CherryPy. I don't understand the basic concept


In short, I don't understand that what happens it CherryPy GETs two requeste to same resource at the same time, are variables mixed or what is happening ?

I have this problem, I am trying to create a very basic web service with Python 2.7 and CherryPy 3.2.2.

Web service is consumed by front end which makes ajax requests to web service with jquery/ajax.

Now, I have created a CherryPy program and I am using its builtin wsgi server. I have CherryPy configuration like this:

conf = {
    'global': {
        'server.socket_host': '127.0.0.1',
        'server.socket_port': 8000,
    },
    '/': {
        'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
    }
}
cherrypy.quickstart(root, '/', conf)

And then I have:

root.customers = getCustomers()

And the actual class for this:

class getCustomers(object):

    def __init__(self):
        pass

    exposed = True

    def GET(self,callback,**kwargs):
        self.callback = callback
        self.cnxn= pyodbc.connect(constr)
        self.cursor = self.cnxn.cursor()

        cherrypy.response.headers['Content-Type']='application/json'
        self.cursor.execute("""select * from customers
            """, self.job_worknumber)
        self.customers = self.cursor.fetchall()

        self.objects_list = []
        for c in self.customers
            r = collections.OrderedDict()
            r['customer_id'] = c.customer_id
            r['customer_name'] = c.customer_name
            self.objects_list.append(r)

        self.cursor.close()
        self.cnxn.close()

        self.w = collections.OrderedDict()
        self.w['data1'] = self.objects_list
        #w['errors'] = 'error'
        self.j = json.dumps(self.w)

        #cursor2.close()
        return  self.callback+'('+self.j+');'

Now when I create a GET request to that I get what I want, but if I create web page which sends two GET request to web service at page load the second request will almost always fail with an error like:

ProgrammingError: Attempt to use a closed cursor.

Or other times:

ProgrammingError: No results.  Previous SQL was not a query

So what is happening, are my requests sharing same variables it they are run at the very same time ? Can I configure CherryPy to only serve one request at a time ?


Solution

  • As @DanielRoseman noticed you should not set variables on self. You have create only one instance of getCustomers class so CherryPy will call GET method on the same instance from multiple threads (there's a thread pool which handles requests). Therfore using

    self.cursor = self.cnxn.cursor()
    

    is not thread-safe and you end up with different cursor in

    self.cursor.execute("""select * from customers
                """, self.job_worknumber)
    

    or self.cursor.fetchall() or in any other place (it is a bit random).

    However changing all variables to local (don't use self at all in GET) should fix the problem.