Desarrollar aplicaciones empresariales con LLM y APIs: arquitectura, herramientas, seguridad y operación · Módulo 3: Contexto, estado y fiabilidad
Diseñar timeouts, reintentos, idempotencia y asincronía
Patrones de fiabilidad para rate limits, fallos de red, respuestas tardías, jobs persistidos, leases y reconciliación.
Objetivo de aprendizaje
Diseñar reintentos limitados, identidad de intención, trabajos asíncronos y reconciliación para recuperarse sin duplicar efectos.
Las APIs de modelos son sistemas remotos. Pueden devolver rate limits, errores transitorios, latencias largas o respuestas que llegan después de que el cliente haya abandonado la conexión.
Una aplicación fiable trata esos sucesos como estados previstos.
Clasifica errores antes de reintentar
No todos los errores son reintentables.
Transitorios: algunos 429, 5xx, fallos de red o timeouts pueden justificar reintento.
Definitivos: credencial inválida, input no aceptado, permiso denegado o regla de negocio fallida necesitan otra acción.
OpenAI documenta rate limits y recomienda diseñar clientes que respeten límites. El número de reintentos debe ser finito y formar parte del presupuesto de tiempo y coste.
Usa backoff con límite
Un patrón razonable:
intento → espera creciente → jitter → nuevo intento
El jitter evita que muchas instancias reintenten al mismo tiempo.
Define:
max_attempts;max_elapsed_time;- errores reintentables;
- límite de coste;
- cancelación.
No conviertas un error persistente en diez llamadas idénticas.
Distingue petición técnica de intención empresarial
El cliente puede repetir la misma operación por:
- doble clic;
- timeout;
- refresh;
- reintento del worker;
- webhook duplicado.
La intención «crear borrador para solicitud 42» necesita un ID estable.
La clave de idempotencia debe representar la misma intención, no simplemente cada HTTP request.
Reconcilia estados inciertos
Un timeout no significa que el proveedor no procesó la solicitud. Cancelar el stream tampoco garantiza que un trabajo remoto se haya cancelado.
Cuando exista estado consultable, reconcilia antes de repetir. Si no existe, diseña la operación para soportar duplicados o evita efectos irreversibles dentro de la llamada.
Esta regla es especialmente importante cuando una respuesta del modelo desencadena tools.
Desacopla trabajos largos
Para procesamiento largo crea un job persistido:
queued
running
succeeded
failed
cancelledPuede necesitar además:
- attempt count;
- locked_by;
- locked_until;
- heartbeat;
- available_at;
- result_ref;
- error_code.
El cliente recibe un job ID y consulta, usa SSE/websocket o recibe un webhook verificado.
Protege workers
Si varios workers consumen la misma cola, la reclamación debe ser atómica. El lease evita que un worker muerto bloquee para siempre una tarea.
Un worker que pierde el lease no debería poder sobrescribir el resultado de otro que recuperó el job.
Define cancelación
Cancelar puede significar:
- dejar de esperar;
- impedir nuevas fases;
- solicitar cancelación remota;
- ignorar un resultado tardío;
- conservarlo para auditoría.
Especifica la semántica. No muestres «cancelado» si el sistema sigue produciendo efectos.
Presupuesta el tiempo total
No configures cada timeout de forma aislada.
Si una operación tiene:
- recuperación;
- llamada LLM;
- tool externa;
- persistencia;
el usuario experimenta la suma.
Define un deadline global y reparte presupuesto por fase. Cuando una fase consume demasiado, las siguientes necesitan saber cuánto queda.
Propaga cancelación
Si el cliente cancela, decide qué componentes reciben la señal.
Un job puede detener:
- nuevas llamadas;
- nuevas tools;
- persistencia opcional.
Pero una tool ya ejecutada puede no ser reversible. La cancelación no debe fingir que los efectos desaparecieron.
Evita tormentas de reintentos
Si cien workers reciben un 429 y reintentan exactamente a los cinco segundos, el sistema puede crear una nueva oleada.
Jitter y límites de concurrencia reducen este patrón.
Además puedes:
- reducir consumidores;
- aplicar circuit breaker;
- degradar funcionalidad;
- pasar trabajos no urgentes a cola.
Diferencia idempotencia de deduplicación
Deduplicar significa reconocer entradas similares o repetidas.
Idempotencia significa que repetir la misma intención produce un efecto controlado.
Dos requests con cuerpos iguales pueden ser intenciones distintas; dos requests con pequeñas diferencias pueden representar la misma intención.
Diseña la clave desde la operación de negocio.
Usa outbox o patrones equivalentes cuando existan varios efectos
Si una transacción guarda estado y después publica un evento, un fallo entre ambos pasos puede dejar inconsistencia.
Patrones como transactional outbox permiten registrar el evento junto con el cambio y publicarlo después de forma recuperable.
No necesitas introducir este patrón en todos los sistemas, pero debes reconocer el problema de dual write cuando existe.
Gestiona poison jobs
Un job puede fallar siempre por datos corruptos.
No lo reintentes infinitamente. Después de max_attempts:
- marca fallo definitivo;
- conserva diagnóstico;
- alerta si es crítico;
- permite intervención;
- evita bloquear la cola.
Mide fiabilidad
Registra:
- tasa de retries;
- retries por causa;
- jobs recuperados;
- jobs expirados;
- duplicados evitados;
- timeouts;
- cancelaciones;
- resultados tardíos.
Estas métricas muestran si el diseño funciona en condiciones reales.
Ejercicio
Construye un adaptador simulado que devuelva:
- 429;
- 500;
- timeout;
- respuesta tardía;
- salida válida.
Implementa:
- clasificación;
- backoff;
- jitter;
- máximo de intentos;
- idempotency key;
- job persistido;
- lease;
- cancelación;
- reconciliación;
- dead-letter o estado final de error.
Resultado de la lección
Debes terminar con una aplicación capaz de sobrevivir a fallos previsibles sin duplicar efectos ni perder el estado. La siguiente capa será seguridad: quién puede pedir qué, qué datos pueden salir y qué contenido puede influir en el modelo.

