Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing tornado and sqlalchemy

I'm trying to write a tornado web application that uses sqlalchemy in some request handlers. These handlers have two parts: one that takes a long time to complete, and another that uses sqlalchemy and is relatively fast. I would like to make the slow part of the request asynchronous, but not the sqlalchemy part. Can I do something like the following code and be safe?

class ExampleHandler(BaseHandler):
    async def post(self):
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(...)   # very slow (no sqlalchemy here)

        with self.db_session() as s:      # sqlalchemy session
            s.add(...)
            s.commit()

        self.render(...)

The idea is to have sqlalchemy still blocking, but have the computational heavy part not blocking the application.

like image 896
Miguel Avatar asked Nov 05 '18 16:11

Miguel


1 Answers

The tornado web server uses asynchronous code to get around the limit of the python Global Interpreter Lock. The GIL, as it is colloquially known, allows only one thread of execution to take place in the python interpreter process. Tornado is able to answer many requests simultaneously because of its use of an event loop. The event loop can perform one small task at a time. Let's take your own post handler to understand this better.

In this handler, when the python interpreter gets to the await keyword, it pauses the execution of the function and queues it for later on its event loop. It then checks the event loop to respond to other events that may have queued up there, like responding to a new connection or servicing another handler.

When you block in an asynchronous function, you freeze the entire event loop as it is unable to pause your function and service anything else. What this actually means for you is that your web server will not accept or service any requests while your async function blocks. It will appear as if your web server is hanging and indeed it is stuck.

To keep the server responsive, you have to find a way to execute your sqlalchemy query in an asynchronous non-blocking manner.

like image 66
Ananth Avatar answered Oct 18 '22 07:10

Ananth