Skip to content

Use Case 11: Proper Cache Lifecycle in FastAPI

Scenario: A microservice uses InMemoryCacheBackend (or Redis) and needs to start the cache cleanup task when the app starts, then shut it down cleanly on termination.


📦 What’s New?

Component Description
ModelRegistry.initialize_cache() Starts the async background task for the registered cache backend.
ModelRegistry.shutdown_cache() Gracefully stops the background task and releases resources.
FastAPI lifespan integration Demonstrates where to call both init and shutdown methods.

🚀 Example

Python
from mongo_ops import MongoConnectionManager, ModelRegistry
from mongo_ops.cache import InMemoryCacheBackend
from contextlib import asynccontextmanager

# Initialise a cache backend (in‑memory example)
cache = InMemoryCacheBackend(max_entries=10_000, default_ttl=300)
ModelRegistry.set_cache_backend(cache)

@asynccontextmanager
async def lifespan(app):
    # Start MongoDB connection and cache background task
    async with MongoConnectionManager.lifespan(
        uri="mongodb://localhost:27017",
        db_name="mydb",
    ):
        await ModelRegistry.initialize_all()   # create indexes
        await ModelRegistry.initialize_cache()  # start cache cleanup
        yield
    # FastAPI will exit the `with` block here – clean up cache
    await ModelRegistry.shutdown_cache()

Why a separate shutdown step?

  • The cache backend may spawn an asyncio.Task that periodically removes expired entries. If the task is left dangling, the event loop may complain about pending tasks on shutdown.
  • shutdown_cache() cancels the internal task and waits for it to finish, ensuring a clean exit.

💡 Tips

  • Register the cache before calling initialize_cache(); otherwise the registry won’t know which backend to start.
  • For Redis backends, the shutdown step also closes the underlying redis.asyncio.Redis client connection.
  • You can also hook the shutdown into a FastAPI @app.on_event("shutdown") handler if you prefer not to use the lifespan context manager.