Thanks! You saved me from a dumb assumption that Tornado methods are
thread safe.
I looked at the code for add_callback(). I see that all it does is
add an item to a set. Sets are thread safe in Python so it makes
sense that add_callback() is thread safe. This is the only method
I'll use from my threads.
Here's my new approach. In this case post() sets up a call to
post_thread() and then post_thread() sets up a call to
post_results().
post() --> post_thread() --> post_results()
The post() and post_results() methods are executed in the main
"thread" under control of IOLoop. These two can call Tornado methods
safely. The post_thread() method is run inside one of the threads
from my thread pool. This is where I can run code with long delays
(e.g. sleep()) without blocking other connections. The only Tornado
methods I will call from post_thread() are add_callback() and
async_callback(). These two methods are thread safe.
This is just one example but demonstrates a general pattern how I can
safely mix threading with Tornado. Right?
@tornado.web.asynchronous
def post(self):
self.user = self.get_argument('username')
taskQueue.put(self.post_thread)
def post_thread(self):
if self.user == 'johnmudd':
# Successful login, nothing else to do for now.
pass
else:
time.sleep(4)
self.user = None
tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.post_results))
def post_results(self):
if self.user:
self.set_secure_cookie('user', self.user)
nextUrl = self.get_secure_cookie('nextUrl')
self.clear_cookie('nextUrl')
if nextUrl == None: nextUrl = '/'
self.redirect(nextUrl) # Calls finish().
else:
raise tornado.web.HTTPError(401, "Auth failed")