I've been investigating graceful shutdowns for uvicorn + FastAPI + fastapi-events (local handler) set.
I noticed that uvicorn can wait for Starlette's background tasks, as well as fastapi-events event handlers but only for events dispatched from the endpoint handler. That is because the dispatch within handler is treated as "outside of request cycle". However, there is no mechanism for tracking the execution of those "outside" events. This means that when uvicorn receives SIGTERM it does not wait for those event handlers to finish. It stops the loop - tasks still receive CancelledError so handler-specific cleanup can still happen. This can lead to situations where some tasks finish (because they're given some time by uvicorn shutdown timeout) whereas others are stopped abruptly.
The situation can be improved if fastapi-events tracks those "outside" events, then plugs into the app lifecycle and waits for the tasks to execute in case of application shutdown.
BTW one more thing that I noticed and I think it's worth mentioning in the docs is that the local even handler is executed only after all Starlette's background tasks are finished. There is no way around it, better not to mix the two :)
I've been investigating graceful shutdowns for uvicorn + FastAPI + fastapi-events (local handler) set.
I noticed that uvicorn can wait for Starlette's background tasks, as well as fastapi-events event handlers but only for events dispatched from the endpoint handler. That is because the dispatch within handler is treated as "outside of request cycle". However, there is no mechanism for tracking the execution of those "outside" events. This means that when uvicorn receives SIGTERM it does not wait for those event handlers to finish. It stops the loop - tasks still receive
CancelledErrorso handler-specific cleanup can still happen. This can lead to situations where some tasks finish (because they're given some time by uvicorn shutdown timeout) whereas others are stopped abruptly.The situation can be improved if fastapi-events tracks those "outside" events, then plugs into the app lifecycle and waits for the tasks to execute in case of application shutdown.
BTW one more thing that I noticed and I think it's worth mentioning in the docs is that the local even handler is executed only after all Starlette's background tasks are finished. There is no way around it, better not to mix the two :)