Giter Site home page Giter Site logo

Potential footgun when using custom `Response(background=<Task()>)` in conjunction with injected `BackgroundTasks` - the custom response overwrites the tasks about fastapi HOT 3 OPEN

Kludex avatar Kludex commented on May 18, 2024
Potential footgun when using custom `Response(background=)` in conjunction with injected `BackgroundTasks` - the custom response overwrites the tasks

from fastapi.

Comments (3)

Kludex avatar Kludex commented on May 18, 2024

I've created the issue because I think we can do better than just ignoring those background tasks. Maybe we can add them to the returned Response object?

from fastapi.

netanel-haber avatar netanel-haber commented on May 18, 2024

That's what I alluded to when I mentioned:

...actually changing this behavior

Meaning, somehow making it so both the injected tasks, and the passed background are executed as expected. For example, is it possible to append thebackground task to the injected tasks? Does FastAPI/Starlette provide a way to get the injections for a given request? Is that available to the Response class (and inheritors like StreamingResponse)?

This is a breaking change because existing apps might find that behavior suddenly changes (=tasks that weren't running before due to this overwrite suddenly run) - like I mentioned, this "breaking change" is really fixing a behavior that doesn't really make sense. But it kind of depends on the repo's policy, I think.

I'd be happy to contribute a pr for this, either way.

from fastapi.

Tintean-Devops avatar Tintean-Devops commented on May 18, 2024

Adding this because it seems related. It is certainly a source of an incredibly obscure bug that had me scratching my head for days. There's nothing in FastAPI that stops you caching a frequently used Response in a variable:

RESPONSE = HTMLResponse('ok')

If you return such a response from an endpoint that adds a background task you get a very obscure bug. This particular task takes a string argument. The first time you call the endpoint everything seems ok. The second time you call it, the background task is invoked with the same argument value as first time. I presume this is because of the same smoke and mirrors noted by @netanel-haber, whereby the Response is actually used to stash the background task context.

Here's a fully worked example:

# wtest.py
import uvicorn
from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import HTMLResponse
import random
import string

RESPONSE = HTMLResponse('ok')

app = FastAPI()

def random_string():
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(20))

async def background_task(arg: str) -> None:
    print(f"{arg=}")

@app.get("/api", response_class=HTMLResponse)
async def api(bk: BackgroundTasks) -> str:
    param = random_string()
    print(f"{param=}")
    bk.add_task(background_task, param)
    return RESPONSE

if __name__ == "__main__":
    uvicorn.run(
        "wtest:app",
        host="0.0.0.0",
        port=80,
        log_level="info",
        reload=True,
    )

Here's the output when you invoke /api twice. param is the parameter passed to the background task and arg is the argument as seen by the task. They should match up. Second time round, they don't:

INFO:     Application startup complete.
param='cmvlzpyrzyzddhmwikri'
INFO:     127.0.0.1:53216 - "GET /api HTTP/1.1" 200 OK
arg='cmvlzpyrzyzddhmwikri'
param='quomuzuwsbjvfqsjamrx'
INFO:     127.0.0.1:53216 - "GET /api HTTP/1.1" 200 OK
arg='cmvlzpyrzyzddhmwikri'```

from fastapi.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.