fastapi: BackgroundTasks not working properly

Describe the bug

The request remains open/active until the background task finishes running, making the purpose of BackgroundTasks kind of useless. On the snippet below the request takes about 10 seconds to complete. I followed the documentation guide but it didnt seem to work.

To Reproduce

async def background_task(text: str, seconds: int):
    import time

    time.sleep(seconds)
    print(text)

@app.get("/run", status_code=status.HTTP_200_OK)
async def test(background_tasks: BackgroundTasks, text: str = "Test", secs: int = 10):
    background_tasks.add_task(background_task, text, secs)
    return {"text": text, "secs": secs}

Screenshot

Screenshot from 2020-04-22 17-16-17

Expected behavior

The request to finish right away and the task to run in background.

Environment

  • OS: Linux Manjaro 19
  • FastAPI Version 0.54.1
  • Python version 3.8.2

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 17 (6 by maintainers)

Most upvoted comments

I’m not 100% sure about this but here’s a few guesses:

  1. Have you tried to run it with await asyncio.sleep(seconds) instead of the time.sleep function? time.sleep is synchronous as far as I know and since background tasks that are defined as “async” just use the event loop as their “background engine”, using a synchronous method in that background task will still globally block the process.

  2. Alternatively, you can try removing the “async” from def background_task. In that case the task should run in a thread pool instead which would then also not block.

@soares7vinicius just fyi this: https://github.com/encode/starlette/issues/436 explains your problem es well. The tldr:

  • async function background task => runs in asyncio loop (everything that doesn’t use “await” will block)
  • normal function background task => runs in a threadpool (and will thus not block in this case)

@tiangolo could this be reopened - while this is an upstream bug, it is not really resolved

i have same issue and if i add

await asyncio.sleep(1) inside any method that is triggered by task, it is working fine. I don’t understand how it can work but it is working. even i put time.sleep(30) after asyncio.sleep, i get result immediately but process finish 30sec later which is correct.

@demonno This is a bug in Starlette - see encode/starlette#919