It seems like the module level variable isn't actually "changed" until the request is completed. I need it to update immediately, so that other requests can be aware that the work is being processed.
Here is an example of the issue:
import cherrypy
import time
@cherrypy.expose
class CherryPySleeps(object):
status = "not sleeping"
@cherrypy.tools.accept(media='text/plain')
def GET(self):
if CherryPySleeps.status == "not sleeping":
CherryPySleeps.status = "sleeping"
time.sleep(10)
CherryPySleeps.status = "not sleeping"
return "I finished sleeping"
else:
return "I am sleeping, shhh"
if __name__ == '__main__':
conf = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on': True,
'tools.response_headers.on': True,
'tools.response_headers.headers': [('Content-Type', 'text/plain')],
}
}
cherrypy.quickstart(CherryPySleeps(), '/', conf)
When I open 2 browser tabs, request the page on the first, then wait a second, then request the page on the second, I get a 10 second pause on each tab, then "I finished sleeping".
What I want is for the second tab to very quickly respond, "I am sleeping, shhh"
If you want to guarantee some synchronicity among the requests (threads), you can use a lock for both read and write (or use the lock in the if
condition). BTW I wasn't able to replicate the exact condition that you described (it worked for me), but at least the lock should guarantee that it will be a consistent result.
Take a look at this example:
import time
import threading
import cherrypy
@cherrypy.expose
class CherryPySleeps(object):
def __init__(self):
# share the same lock among read and write operations,
# the read is not "strictly" required, but you can use
# it to make sure there is no write happening at the
# same time
self._status_lock = threading.Lock()
# the internal status variable
self._status = "not sleeping"
@property
def status(self):
with self._status_lock:
return self._status
@status.setter
def status(self, new_status):
with self._status_lock:
self._status = new_status
@cherrypy.tools.accept(media='text/plain')
def GET(self):
if self.status == "not sleeping":
self.status = "sleeping"
time.sleep(10)
self.status = "not sleeping"
return "I finished sleeping"
else:
return "I am sleeping, shhh"
if __name__ == '__main__':
conf = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on': True,
'tools.response_headers.on': True,
'tools.response_headers.headers': [('Content-Type', 'text/plain')],
}
}
cherrypy.quickstart(CherryPySleeps(), '/', conf)
There are other ways to do it, using the plugin system in CherryPy, but I think that for this example is not necessary.