Reading the Tornado documentation, it\'s very clear how to call an async function to return a response:
class GenAsyncHandler(RequestHandler):
@gen.corou
Here's my answer in 2019!
Start with some slow non-blocking code. See: http://www.tornadoweb.org/en/stable/faq.html#id2
async def _do_slow_task(self, pk):
await asyncio.sleep(pk)
logger.info(f'Finished slow task after {pk} seconds')
See here to understand the difference between async and blocking: http://www.tornadoweb.org/en/stable/guide/async.html#asynchronous-and-non-blocking-i-o
Then, make your request method a coroutine with the async/await syntax, which makes it non-blocking in order to handle multiple requests in parallel.
async def post(self):
"""Make a few requests with different pks and you should see that
the numbers logged are in ascending order.
"""
pk = self.get_query_argument('pk')
try:
record = await self.db_queryone(
f"SELECT * FROM records WHERE id = {int(pk)};"
)
except Exception as e:
self.set_status(400)
self.write(str(e))
return
await self._do_slow_task(pk)
self.write(f'Received {pk}')
Now, modify the method a bit to run in the background or
“fire and forget” a coroutine without waiting for its result
so that the client receives a response right away. See: http://www.tornadoweb.org/en/stable/guide/coroutines.html#how-to-call-a-coroutine
async def post(self):
"""Make a few requests with different pks and you should see responses
right away, and eventually log messages with the numbers in
ascending order.
"""
pk = self.get_query_argument('pk')
try:
record = await self.db_queryone(
f"SELECT * FROM records WHERE id = {int(pk)};"
)
except Exception as e:
self.set_status(400)
self.write(str(e))
return
IOLoop.current().spawn_callback(self._do_slow_task, pk)
self.write(f'Received {pk}')