Skip to content

Knowledgebase

Managing FastAPI lifespan resources and database pools

development, performance

Shared clients and database pools should be initialised and closed through the application lifecycle. Creating an uncontrolled pool for every request can exhaust connections and leave resources behind.

What you need before you begin

Identify the resources required by each worker and the connection limits of their services. Check how the installed application uses the supported FastAPI lifespan mechanism.

01 Manage FastAPI lifespan resources and database pools

  1. Create the required clients or pools in a lifespan context and make them available through the application’s dependency pattern.

  2. Close the resources during lifespan shutdown. Avoid assuming that a module import provides a complete startup and cleanup lifecycle.

  3. Set finite pool sizes and connection timeouts. Multiply those limits by the number of worker processes when checking the total database or API demand.

  4. Keep startup checks limited and observable. A failed essential dependency can prevent readiness, while optional services may need a deliberate degraded mode.

  5. Test startup, normal requests and graceful shutdown, including a deployment that replaces the running processes.

02 Example: open and close one bounded client per worker

This FastAPI lifespan pattern creates a reusable HTTPX client for each application process and closes it at shutdown. Merge it into the project's existing lifecycle rather than creating another app object alongside it.

Code or configuration example
from contextlib import asynccontextmanager
import httpx
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    limits = httpx.Limits(
        max_connections=10, max_keepalive_connections=5
    )
    async with httpx.AsyncClient(timeout=10.0, limits=limits) as client:
        app.state.http_client = client
        yield

app = FastAPI(lifespan=lifespan)

Application dependencies can retrieve this client from the request's app state for approved outgoing calls. The example does not issue any external request. Its limits apply per worker, so four workers could create four separate pools.

Test startup, a controlled request and graceful shutdown. Verify that resources close after shutdown and a new worker creates a fresh usable client. Apply the same deliberate lifecycle principle using your database library's own supported pool and disposal API.

Confirm the expected result

Observe the expected number of database connections while idle and under load. Confirm they close after the service stops and that a restarted worker creates fresh usable resources.

Troubleshoot unexpected results

A connection count that grows per request can indicate clients are repeatedly created without cleanup. Inspect the dependency lifecycle before merely increasing the database limit.

A common question

Will one lifespan-created object be shared by every worker?

Each process normally has its own memory and resources. Budget pools and large loaded objects per worker unless the architecture explicitly uses an external shared service.

Was this answer helpful?

Need a little more help?

Our support team can help you find the next step.

Contact support

Powered by WHMCompleteSolution