Usar caché local en Flask con lru_cache para acelerar respuestas

  Planteamiento del problema

Tienes una API en Flask que tarda hasta 5 minutos en responder. Esto afecta gravemente la experiencia de usuario y genera cuellos de botella en el sistema.

  Objetivo

Mejorar el tiempo de respuesta de una API lenta utilizando caché en memoria con functools.lru_cache, evitando procesamientos repetitivos.

Aquí algunas estrategias para reducir el tiempo de respuesta en una API lenta:

  Objetivo

  1. Optimización del backend: Mejora la lógica del servidor identificando y corrigiendo cuellos de botella.
  2. Uso de caché: Guarda respuestas frecuentes para no hacer consultas repetidas al backend o a APIs externas.
  3. Mejoras en la base de datos: Revisa índices, normalización y estructura de tus queries.
  4. Escalabilidad: Usa más recursos de hardware o escalabilidad horizontal si tienes alta demanda.
  5. Procesamiento asíncrono: No bloquees al usuario con tareas que pueden ejecutarse en segundo plano.

Si trabajas con una API externa y no tienes control sobre ella:

  Objetivo

  1. Caché local: Almacena temporalmente las respuestas en tu app para evitar repetir llamadas innecesarias.
  2. Solicitudes concurrentes: Si necesitas múltiples recursos, usa concurrencia para no esperar una por una.
  3. Optimización de datos solicitados: Pide solo lo necesario usando filtros o parámetros.
  4. Proxy intermedio: Crea un servidor proxy que maneje, almacene y optimice las respuestas de la API.

Caso real de una API lenta

Una función que simula una llamada lenta (como una API externa que tarda) puede optimizarse aplicando caché en memoria para evitar que se repita.

python
from flask import Flask, request
import time
import functools

app = Flask(__name__)

# Simula una llamada costosa (como una API externa lenta)
def llamada_lenta_api(param):
  print(f"Consultando API con {param}...")
  time.sleep(5)  # Simula espera de 5 segundos
  return f"Resultado para {param}"

# Aplica caché en memoria: guarda el resultado para evitar repetirlo
@functools.lru_cache(maxsize=128)
def obtener_datos(param):
  return llamada_lenta_api(param)

# Ruta de la API
@app.route("/datos")
def datos():
  ciudad = request.args.get("ciudad", "bogota")  # Lee parámetro ?ciudad=
  resultado = obtener_datos(ciudad)
  return {"ciudad": ciudad, "resultado": resultado}

# Ejecuta la app
if __name__ == "__main__":
  app.run(debug=True)
  Explicación paso a paso

1. @functools.lru_cache(maxsize=128)

  • Decora la función para guardar sus resultados en caché.
  • Si la función ya se ejecutó con un argumento específico, devuelve el resultado almacenado en memoria.
  • maxsize=128: guarda hasta 128 combinaciones únicas antes de reemplazar.

2. llamada_lenta_api(param)

  • Simula una operación lenta (por ejemplo, acceso a base de datos o a una API externa).

3. obtener_datos(param)

  • Encapsula la llamada lenta y la protege con la caché.

4. @app.route("/datos")

  • Endpoint /datos que recibe un parámetro ciudad.
  • Devuelve el resultado en JSON, usando caché si ya fue consultado.

Cómo probarlo

1. Ejecuta el script:

bash
python app.py

2. Prueba la API:

bash
# Primera llamada (tarda 5 segundos)
http://localhost:5000/datos?ciudad=bogota

# Segunda llamada (instantánea gracias al caché)
http://localhost:5000/datos?ciudad=bogota
  Conclusión

functools.lru_cache es una herramienta poderosa y simple para mejorar el rendimiento cuando se repiten solicitudes similares. Perfecto para desarrollo local o cuando se manejan datos que cambian poco.