I’d like to use aioredis in a Tornado application. However, I couldn’t figure out a way to implement an async startup and shutdown of its resources since the Application class has no ASGI Lifespan events such as in Quart or FastAPI.
In other words, I need to create a Redis pool before the app starts to serve requests and release that pool right after the app has finished or is about to end. The problem is that the aioredis pool creation is asynchronous, but the Tornado Application creation is synchronous.
The basic application looks like this:
import os
from aioredis import create_redis_pool
from aioredis.commands import Redis
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.web import Application
from .handlers import hello
redis: Redis = None
async def start_resources() -> None:
'''
Initialize resources such as Redis and Database connections
'''
global redis
REDIS_HOST = os.environ['REDIS_HOST']
REDIS_PORT = os.environ['REDIS_PORT']
redis = await create_redis_pool((REDIS_HOST, REDIS_PORT), encoding='utf-8')
async def close_resources() -> None:
'''
Release resources
'''
redis.close()
await redis.wait_closed()
def create_app() -> Application:
app = Application([
("/hello", hello.HelloHandler),
])
return app
if __name__ == '__main__':
app = create_app()
http_server = HTTPServer(app)
http_server.listen(8000)
IOLoop.current().start()
It is important that I can use the startup and shutdown functions during tests too.
Any ideas?
2
Answers
The response from xyres is correct and put me on the right track. I only think it could be improved a little, so I am posting this alternative:
Also, to use this code in testing with
pytest
andpytest-tornado
, you should create aconftest.py
file like this:Note that it is important to declare
io_loop
as a dependency injection.To create the pool, call your coroutine using
run_sync
before you start the loop:To destroy the pool before the program exits, use a
try...finally
block so that abrupt exits due to unhandled exceptions are also accounted for: