tortoise / tortoise/tortoise-orm

Tortoise + FastAPI StreamingResponse returns WRONG query results

Open
#1,984 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
5.6k
Forks
516
Avg merge
2d 21h
Merged PRs (30d)
9

Description

Describe the bug

When a client aborts the connection during streaming response, tortoise may return the wrong query results in the next requests.

I see a similar issue: https://github.com/tortoise/tortoise-orm/issues/1698

To Reproduce

import asyncio
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from tortoise import fields, models
from tortoise.contrib.fastapi import register_tortoise


class User(models.Model):
    id = fields.IntField(pk=True)
    username = fields.CharField(max_length=50)


@asynccontextmanager
async def lifespan(app: FastAPI):
    has_user = await User.all().count()
    if not has_user:
        await User.create(username="John")
    yield


app = FastAPI(lifespan=lifespan)

register_tortoise(
    app,
    db_url="mysql://root@localhost/test",
    modules={"models": ["main"]},
    generate_schemas=True,
)


@app.get("/users", response_model=None)
async def check_users():

    exists = await User.exists()  # will return False in the 2nd round
    assert exists == True

    exists = await User.exists()
    assert exists == True

    exists = await User.exists()
    assert exists == True

    async def generate():
        try:
            await asyncio.sleep(600)
            yield "hello"
        finally:
            await User.exists(id=0)  # not exists, should return False

    return StreamingResponse(generate())

  1. Launch the FastAPI server:
fastapi dev main.py
  1. Make an initial request (this will hang):
curl localhost:8000/users
  • The request will remain pending - don't wait for completion
  • Terminate the curl process with Ctrl+C after a few seconds
  1. Repeat the same request:
curl localhost:8000/users

The issue will now manifest. An AssertionError will be thrown

  File "/Users/work/.pyenv/versions/3.11.11/lib/python3.11/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/work/test/main.py", line 37, in check_users
    assert exists == True
           ^^^^^^^^^^^^^^
AssertionError

Additional context
fastapi==0.115.12
tortoise-orm[asyncmy]==0.24.2
tortoise==0.1.1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the FastAPI /users reproduction shown in main.py, using the listed Tortoise and FastAPI versions and MySQL configuration. Abort the first streaming curl request, repeat it, and verify that the three User.exists() assertions remain true and the final id=0 check remains false.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, mysql, python
Domain
api, backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.