Planteamiento y alcance
El endpoint de arranque orquesta tres llamadas hacia servicios descendentes (downstream). El perfil y los permisos son obligatorios para una estructura base (shell) correcta; el feed puede estar desactualizado o ausente. El endpoint debe devolver una respuesta tipada que permita al cliente renderizar secciones seguras de forma independiente. El presupuesto p95 de 300 ms incluye la sobrecarga de orquestación, y el diseño debe indicar qué datos se pueden almacenar en caché y por cuánto tiempo.
Qué está evaluando el entrevistador
- Derivar paralelismo, presupuestos de tiempo de espera (timeouts) y semántica de fallos a partir de los requisitos visibles para el usuario.
- Distinguir entre datos faltantes, un resultado vacío y un error de dependencia.
- Componer reintentos, disyuntores (circuit breakers), mamparas de aislamiento (bulkheads) y políticas de caché sin multiplicar la carga.
- Diseñar un contrato de respuesta evolutivo y señales operativas útiles.
Preguntas aclaratorias para hacer
Pregunte si los permisos pueden estar desactualizados, si los datos del feed tienen un límite de frescura, si el cliente puede renderizar de forma progresiva y si las llamadas comparten un contexto de inquilino (tenant) o autorización. Si nunca se permite que los permisos estén desactualizados, permanecen en la ruta crítica; si el feed tiene un objetivo de frescura de cinco minutos, una caché de tipo stale-while-revalidate puede proteger la latencia.
La respuesta de 30 segundos
Haría que la pasarela (gateway) autentique una sola vez, distribuya en paralelo (fan-out) las llamadas de perfil, permisos y feed, y reserve un límite de tiempo (deadline) para el ensamblado. Las secciones obligatorias fallan de forma cerrada (fail closed); las secciones opcionales devuelven un estado no disponible explícito con un código de motivo y una marca de tiempo de frescura. Los reintentos se limitan a llamadas transitorias e idempotentes y consumen un presupuesto compartido. Los tiempos de espera por dependencia, bulkheads, disyuntores, caché de datos obsoletos y una envoltura tipada con detalles del problema evitan que una sola caída deje la estructura base en blanco. Las métricas rastrean el éxito a nivel de sección, el agotamiento del deadline, las entregas desde caché obsoleta y la saturación de dependencias.
Análisis detallado paso a paso
1. Establecer el presupuesto de tiempo y concurrencia
A 2.000 solicitudes por segundo, tres llamadas secuenciales desperdician el presupuesto de 300 ms. Distribuya concurrentemente en paralelo, asigne a cada dependencia un límite de tiempo inferior al deadline general y mantenga el ensamblado más la serialización dentro del tiempo restante. Utilice grupos de conexiones acotados y una señal de cancelación por solicitud para que una dependencia cuyo tiempo se agotó deje de consumir trabajo.
2. Definir la semántica de respuesta parcial
Devuelva una envoltura estable con un estado para cada sección: ready, stale o unavailable. Incluya un motivo legible por máquina y una marca de tiempo de los datos, pero no filtre nombres de host internos. Los errores de perfil o permisos deben fallar de forma cerrada o devolver un estado de inicio de sesión/acción; un tiempo de espera agotado en el feed puede dejar la estructura base utilizable. Un objeto de error que siga la RFC 9457 puede describir fallos a nivel de toda la solicitud sin fingir que fallaron todas las secciones.
3. Proteger las dependencias de reintentos y caídas
Reintente únicamente fallos transitorios, solo para lecturas idempotentes y solo una vez dentro de un deadline compartido. Añada variación aleatoria (jitter) y detenga los reintentos cuando el circuito esté abierto. Los bulkheads limitan las llamadas concurrentes por dependencia; una caché obsoleta o un valor predeterminado acotado maneja los datos opcionales del feed. Un disyuntor es útil cuando los fallos repetidos downstream consumirían de otro modo toda la capacidad del gateway, pero no reemplaza a los tiempos de espera ni a un sondeo de recuperación.
4. Evolucionar y observar el contrato
Agregue versiones a los campos de manera aditiva, permita que los clientes ignoren secciones desconocidas e incluya un identificador de correlación de solicitud. Registre la latencia de dependencias, la causa del tiempo de espera agotado, el estado del circuito, la antigüedad de la caché, el estado de la sección y el tamaño de la carga útil (payload). Rastree el árbol de distribución concurrente, tome muestras de solicitudes lentas y genere alertas sobre la tasa de fallos de secciones obligatorias, la antigüedad de datos obsoletos y el volumen de reintentos. Las pruebas de contrato deben cubrir resultados mixtos como permisos listos, perfil desactualizado y feed no disponible.
Un ejemplo de respuesta sólida
Aclararía la frescura y si se permite el renderizado progresivo. El gateway autentica una vez, distribuye en paralelo tres lecturas y asigna deadlines por llamada dentro de un presupuesto general de 300 ms. Devuelve estados a nivel de sección como ready, stale o unavailable. La identidad y los permisos obligatorios fallan de forma cerrada; los datos del feed pueden provenir de una caché obsoleta acotada. Se permite un único reintento con jitter solo para lecturas idempotentes transitorias, protegido por un bulkhead y un disyuntor por dependencia. Las métricas y trazas exponen los fallos de sección y la presión sobre el deadline, mientras que el versionado aditivo mantiene funcionando a los clientes más antiguos.
Errores comunes
- Llamar a las dependencias secuencialmente → la latencia se acumula superando el presupuesto → distribuya en paralelo con grupos acotados y deadlines.
- Devolver HTTP 200 con nulos ambiguos → el cliente no puede distinguir entre datos vacíos y un fallo → use estados de sección explícitos y códigos de motivo.
- Reintentar cada error en cada capa → una caída se convierte en una tormenta de reintentos → clasifique los errores y aplique un único presupuesto de reintentos compartido.
- Almacenar permisos en caché sin una política → el acceso puede durar más que su autorización → defina un límite de frescura o falle de forma cerrada.
- Usar un solo circuito global → una caída del feed bloquea los datos de identidad → aísle disyuntores y bulkheads por dependencia.
- Registrar solo la latencia total → los fallos opcionales y obligatorios son indistinguibles → emita métricas y trazas a nivel de sección.
Preguntas de seguimiento y respuestas
El feed es lento pero el usuario necesita la estructura base inmediatamente. ¿Qué cambia?
Acorte el deadline del feed, entregue un resultado obsoleto acotado cuando su antigüedad sea aceptable y devuelva unavailable en caso contrario. Mantenga la respuesta de la estructura base independiente para que el cliente pueda cargar el feed más tarde.
Los datos de permisos están desactualizados en una región. ¿Puede entregarlos?
Solo si la política de autorización permite explícitamente esa desactualización y la respuesta comunica su antigüedad. Para acciones sensibles, vuelva a verificar contra una fuente autoritativa y falle de forma cerrada ante la incertidumbre.
¿Cómo evita que un reintento se extienda más allá de los 300 ms?
Pase un deadline absoluto a través del contexto de distribución en paralelo. Antes de cada reintento, reserve tiempo para el intento y el ensamblado; si no queda tiempo, devuelva el estado de tiempo de espera agotado de la sección en lugar de iniciar un trabajo que no puede finalizar.
Una dependencia se recupera después de que se abre el circuito. ¿Cómo se restaura el tráfico?
Tras un período de enfriamiento, envíe una pequeña cantidad de sondeos semiabiertos. Cierre el circuito únicamente después de que los sondeos exitosos cumplan con los mismos criterios de tiempo de espera y error; de lo contrario, manténgalo abierto con un tiempo observable para el siguiente sondeo.