tortoise / aerich

A database migrations tool for TortoiseORM, ready to production.
https://github.com/tortoise/aerich
Apache License 2.0
804 stars 90 forks source link

Aerich hangs on init-db with sqlite #268

Closed dmi-dmi-dmi closed 1 year ago

dmi-dmi-dmi commented 1 year ago

I took Starlette example from Tortoise docs in order to test aerich and noticed that init-db hangs at least with sqlite

Steps to reproduce

Install dependencies

``` aerich==0.7.0 aiosqlite==0.17.0 starlette==0.20.4 tortoise-orm==0.19.2 ```

Create main.py

``` # pylint: disable=E0401,E0611 import logging from json import JSONDecodeError from starlette.applications import Starlette from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.responses import JSONResponse from starlette.status import HTTP_201_CREATED, HTTP_400_BAD_REQUEST from uvicorn.main import run from tortoise.contrib.starlette import register_tortoise from tortoise import fields, models class Users(models.Model): id = fields.IntField(pk=True) username = fields.CharField(max_length=20) def __str__(self) -> str: return f"User {self.id}: {self.username}" logging.basicConfig(level=logging.DEBUG) app = Starlette() @app.route("/", methods=["GET"]) async def list_all(_: Request) -> JSONResponse: users = await Users.all() return JSONResponse({"users": [str(user) for user in users]}) @app.route("/user", methods=["POST"]) async def add_user(request: Request) -> JSONResponse: try: payload = await request.json() username = payload["username"] except JSONDecodeError: raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="cannot parse request body") except KeyError: raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="username is required") user = await Users.create(username=username) return JSONResponse({"user": str(user)}, status_code=HTTP_201_CREATED) TORTOISE_ORM = { "connections": {"default": "sqlite://test.db"}, "apps": { "models": { "models": [__name__, "aerich.models"], "default_connection": "default", }, }, } register_tortoise(app, config=TORTOISE_ORM) if __name__ == "__main__": run(app) ```

After that try to create migrations and init db with the following commands

> aerich init -t main.TORTOISE_ORM
Success create migrate location ./migrations
Success write config to pyproject.toml

> aerich init-db
DEBUG:tortoise:Tortoise-ORM startup
    connections: {'default': 'sqlite://test.db'}
 .... omitted logging output for clarity ...
 Success create app migrate location migrations/models
Success generate schema for app "models"
^CException ignored in: <module 'threading' from '/usr/lib/python3.10/threading.py'>
Traceback (most recent call last):
  File "/usr/lib/python3.10/threading.py", line 1567, in _shutdown
    lock.acquire()
KeyboardInterrupt: 

init-db hangs forever until I do Ctrl-C

jtraub commented 1 year ago

Well, I was wrong thinking that the problem has been caused by Tortoise ORM. It is a problem in Aerich code caused by the fact that init-db doesn't close connection to database.

It seems that the problem has appeared in this commit https://github.com/tortoise/aerich/commit/d4430cec0def817de059b73c7f486810dfb8cc46

Intended goal was to revert this specific change https://github.com/tortoise/aerich/commit/801dde15be40a1252892e7a43f3aa7b105d31ba8#diff-4b977aa5b924426bc9f5531e8e3cd7567428c87b979f9011953b3c77014d3084

Notice that initially wrapper didn't close connections if wrapped function has name of either cli or init which makes sense as these functions do not connect to the db

Hotfix for some reason changed init to init_db (i guess it was just a typo) - hence causing hang for your case.