Concepto clave
Los eventos de inicio y cierre en FastAPI son hooks que permiten ejecutar código específico cuando tu aplicación se inicia o se detiene. Piensa en ellos como el protocolo de encendido y apagado de una fábrica: al arrancar, verificas que todas las máquinas estén operativas y cargas los materiales necesarios; al cerrar, aseguras que todo quede limpio y los recursos liberados para evitar fugas o daños.
En el contexto de desarrollo backend, estos eventos son cruciales para la gestión de recursos como conexiones a bases de datos, pools de clientes HTTP, o servicios externos. Sin ellos, podrías enfrentar problemas como conexiones huérfanas que consumen memoria o servicios que no se desconectan correctamente, llevando a inestabilidad en producción. El evento de inicio (startup) se ejecuta una vez, justo antes de que FastAPI comience a aceptar solicitudes, mientras que el evento de cierre (shutdown) corre cuando la aplicación se detiene, idealmente liberando todo lo adquirido.
Cómo funciona en la práctica
FastAPI proporciona decoradores integrados para registrar funciones como eventos. Para el inicio, usas @app.on_event("startup"), y para el cierre, @app.on_event("shutdown"). Estos decoradores se aplican a funciones asíncronas o síncronas que realizan tareas específicas. Por ejemplo, al iniciar, podrías establecer una conexión a PostgreSQL y crear un pool reutilizable; al cerrar, cerrarías ese pool y desconectarías cualquier cliente de Redis.
Un flujo típico implica: 1) Definir las funciones de evento con lógica clara y manejos de errores, 2) Registrar estas funciones usando los decoradores en tu instancia de FastAPI, y 3) Asegurar que las operaciones sean atómicas y no bloqueen el ciclo de vida de la aplicación. En entornos avanzados, esto se combina con inyección de dependencias para recursos compartidos, optimizando el rendimiento y la escalabilidad.
Codigo en accion
Aquí un ejemplo funcional que muestra cómo configurar eventos para gestionar una conexión a una base de datos y un cliente de caché:
from fastapi import FastAPI
import asyncpg
import aioredis
from contextlib import asynccontextmanager
# Configuración inicial sin eventos (ANTES)
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hola Mundo"}
# Refactorización con eventos (DESPUÉS)
# Usamos lifespan para un manejo más moderno y limpio
@asynccontextmanager
async def lifespan(app: FastAPI):
# Evento de inicio: conectar a PostgreSQL y Redis
print("Iniciando aplicación...")
app.state.db_pool = await asyncpg.create_pool(
"postgresql://user:pass@localhost/dbname"
)
app.state.redis = await aioredis.from_url("redis://localhost")
yield
# Evento de cierre: cerrar conexiones
print("Cerrando aplicación...")
await app.state.db_pool.close()
await app.state.redis.close()
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
# Usar recursos en endpoints
async with app.state.db_pool.acquire() as connection:
result = await connection.fetch("SELECT * FROM items")
return {"data": result}Este código demuestra la transición de una app básica a una con gestión robusta de recursos, usando el método recomendado lifespan para un control más fino.
Errores comunes
- No manejar excepciones en eventos: Si una conexión falla al iniciar, la app podría arrancar en un estado inconsistente. Siempre incluye try-except para registrar errores y fallar rápido si es crítico.
- Bloquear el evento de inicio con operaciones síncronas largas: Esto retrasa el arranque de la API. Usa funciones asíncronas o ejecuta tareas pesadas en segundo plano.
- Olvidar liberar recursos en el cierre: Conexiones a BD o sockets abiertos pueden causar fugas de memoria. Asegúrate de que cada adquisición en el inicio tenga su liberación correspondiente.
- Usar eventos para lógica de negocio: Los eventos son para gestión de recursos, no para procesar datos de usuarios. Evita mezclar responsabilidades.
- Ignorar el orden de ejecución: En apps complejas, múltiples eventos pueden registrarse; define dependencias claras si un recurso necesita otro para inicializar.
Checklist de dominio
- ¿Puedes configurar eventos de inicio y cierre usando tanto decoradores como el método lifespan?
- ¿Sabes integrar al menos dos tipos de recursos externos (ej., BD y caché) en estos eventos?
- ¿Implementas manejo de errores robusto para fallos durante la inicialización o cierre?
- ¿Eres capaz de refactorizar una app existente para incluir gestión de recursos vía eventos?
- ¿Puedes explicar la diferencia entre eventos síncronos y asíncronos en este contexto?
- ¿Verificas que todos los recursos se liberen correctamente en simulaciones de cierre?
- ¿Documentas los eventos y sus propósitos en tu código para mantenibilidad?
Implementar eventos de ciclo de vida para un microservicio con FastAPI y MongoDB
En este ejercicio, crearás una API avanzada que gestione conexiones a MongoDB y un cliente de email usando eventos de inicio y cierre. Sigue estos pasos:
- Crea un nuevo proyecto FastAPI e instala las dependencias:
fastapi,uvicorn,motor(para MongoDB asíncrono), yaiohttp(para cliente HTTP). - Define una función
lifespanusando@asynccontextmanagerque, al iniciar, establezca una conexión a MongoDB (usando Motor) y un cliente aiohttp para enviar emails. - En el evento de inicio, verifica que la conexión a MongoDB sea exitosa; si falla, lanza una excepción para evitar que la app arranque. Para el cliente aiohttp, configura un timeout de 10 segundos.
- Registra estos recursos en
app.statepara acceso global en los endpoints. - Crea un endpoint
POST /itemsque inserte un documento en MongoDB y, en paralelo, use el cliente aiohttp para simular un email de notificación (puede ser un log). - En el evento de cierre, cierra ambas conexiones de manera segura, asegurándote de que no queden tareas pendientes.
- Prueba la app iniciándola con uvicorn, ejecutando una solicitud al endpoint, y luego deteniéndola para verificar que los recursos se liberen (usa logs para confirmar).
- Recuerda que Motor requiere un manejo asíncrono; usa 'await' al conectar y cerrar.
- Para el cliente aiohttp, considera usar 'aiohttp.ClientSession' y cerrarlo en el cierre.
- Agrega prints o logs en cada fase del lifespan para depurar el flujo de eventos.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.