Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanic-like background tasks #4475

Closed
9 tasks done
anna-hope opened this issue Jan 24, 2022 · 5 comments
Closed
9 tasks done

Sanic-like background tasks #4475

anna-hope opened this issue Jan 24, 2022 · 5 comments

Comments

@anna-hope
Copy link

anna-hope commented Jan 24, 2022

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

# this is part of a Sanic application code
# please read description/wanted code for details

async def poll_for_config_updates(app):
    polling_interval = app.config.CONFIG_UPDATE_POLL_INTERVAL  # e.g. 60s
    while True:
        await app.ctx.config_registry.update_configs()
        await asyncio.sleep(polling_interval)


@app.before_server_start
async def get_configs(app, loop):
    app.add_task(poll_for_config_updates)

Description

In Sanic, the concept of a background task refers to something different than in FastAPI -- namely, the ability to add a task to the event loop outside of the request/response concept, such as on server start.

From Sanic docs:

async def notify_server_started_after_five_seconds():
    await asyncio.sleep(5)
    print('Server successfully started!')

app.add_task(notify_server_started_after_five_seconds())

You can check out Sanic docs for more details.

In one of my applications, I use this kind of background task to run an async function that checks for updates to certain configs in the Firestore database. You can see sample code for that task above. This task runs on server start, and stays in the background for the whole life of the application.

Wanted Solution

I am exploring migrating this application from Sanic to FastAPI, and would like the ability to run this kind of background task. It's unfortunate that the term "background tasks" in FastAPI/Starlette becomes overloaded. FastAPI could call them 'async tasks' or something else.

I'm also not sure how this plays into FastAPI seemingly not having the concept of an application context (assuming that is still the case?)

Wanted Code

from fastapi import FastAPI

app = FastAPI()

# ... same async function as above

@app.on_event("startup")
async def startup_event():
    app.add_task(poll_for_config_updates)  # like in Sanic (the method could have another name)

Alternatives

Perhaps using Depends as described here?

Operating System

Linux, macOS

Operating System Details

No response

FastAPI Version

0.72.0

Python Version

Python 3.9.7

Additional Context

No response

@anna-hope anna-hope added the feature New feature or request label Jan 24, 2022
@Kludex
Copy link
Sponsor Collaborator

Kludex commented Jan 25, 2022

I'm also not sure how this plays into FastAPI seemingly not having the concept of an application context (assuming that is still the case?)

That's still the case. Not FastAPI's issue, but actually the server itself.

Why running a long task using asyncio, anyio or trio doesn't satisfy your needs? Or the idea is to have an interface for those kind of tasks?

@ahnaf-zamil
Copy link

For asynchronous tasks, I personally use Celery. There are also FastAPI + Celery specific tutorials available online as well :D

https://testdriven.io/blog/fastapi-and-celery/

@jgould22
Copy link

Why running a long task using asyncio, anyio or trio doesn't satisfy your needs? Or the idea is to have an interface for those kind of tasks?

Something like that may be nice.

The use case I have is I have some infrequently updated database information that the application needs but I don't want to request the data all the time as it only changes once a day or so.

I would like to periodically update these values.

@dstlny
Copy link

dstlny commented Jan 25, 2022

Why running a long task using asyncio, anyio or trio doesn't satisfy your needs? Or the idea is to have an interface for those kind of tasks?

Something like that may be nice.

The use case I have is I have some infrequently updated database information that the application needs but I don't want to request the data all the time as it only changes once a day or so.

I would like to periodically update these values.

Sanic just wraps asyncio.create_task, anyway.

https://github.com/sanic-org/sanic/blob/ac388d644b1e22156e228470fad8ea34932c080a/sanic/app.py#L1159

from fastapi import (
	FastAPI as BaseFastAPI
)
import asyncio

class FastAPI(BaseFastAPI):

	def add_task(
		self,
                coro,
	):
		asyncio.create_task(coro)

@anna-hope
Copy link
Author

Sanic just wraps asyncio.create_task, anyway.

Sanic does a bit more than just wrap asyncio.create_task: https://github.com/sanic-org/sanic/blob/ac388d644b1e22156e228470fad8ea34932c080a/sanic/app.py#L1197 For one, it makes sure that the tasks are only added to the loop after the application/loop starts. It then also handles the case where those tasks are delayed, if they were scheduled before the loop started.

It also keeps track of those tasks in a registry, and cleans them up when the application shuts down.

That's probably something that can be manually copied too, but it would be nice for that to be handled by the framework.

Or the idea is to have an interface for those kind of tasks?

Yes, that's the idea 🙂 Like with Sanic, it would be great if the application could keep track of and handle the cleanup of the async tasks instead of having to do it manually -- although I do understand that for some cases that might not be too hard.

@tiangolo tiangolo added question Question or problem reviewed question-migrate and removed feature New feature or request labels Feb 23, 2023
Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #8568 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests

6 participants