22. Manejo de errores, timeouts y reintentos

22.1 Introducción

Una integración no debe probarse solo cuando todo funciona. Las dependencias pueden fallar, responder tarde, rechazar datos, estar mal configuradas o devolver errores temporales.

El manejo de errores, timeouts y reintentos define cómo se comporta el sistema cuando una colaboración no sale como se esperaba. Probar estos casos es fundamental para evitar estados inconsistentes, operaciones duplicadas y fallas difíciles de diagnosticar.

En este tema veremos cómo diseñar pruebas de integración para situaciones de error y recuperación.

22.2 Por qué probar errores

Muchos defectos graves aparecen en caminos alternativos, no en el camino exitoso. Una integración puede funcionar bien cuando la dependencia responde correctamente, pero fallar mal cuando algo sale de lo normal.

Probar errores permite verificar que el sistema:

  • No deje datos parciales incorrectos.
  • No oculte fallas importantes.
  • No repita operaciones peligrosas.
  • Informe el problema de forma clara.
  • Registre evidencia para diagnóstico.
  • Sepa cuándo reintentar y cuándo no.
Una integración robusta no es la que nunca falla, sino la que falla de manera controlada cuando una dependencia no responde como se espera.

22.3 Tipos de errores

Conviene distinguir tipos de errores porque no todos deben tratarse igual.

Tipo Ejemplo Tratamiento habitual
Error de validación Datos obligatorios faltantes. Rechazar operación y explicar el problema.
Error de negocio Stock insuficiente. No continuar y mantener estado coherente.
Error temporal Servicio externo no responde por unos segundos. Reintentar o dejar pendiente según la regla.
Error permanente Credencial inválida o contrato incompatible. No reintentar indefinidamente; registrar y reportar.
Error inesperado Respuesta con formato desconocido. Manejar de forma segura y registrar evidencia.

22.4 Timeouts

Un timeout ocurre cuando una operación tarda más de lo permitido. Es importante porque una aplicación no puede esperar indefinidamente a una dependencia.

Una prueba de integración puede verificar:

  • Que exista un tiempo máximo configurado.
  • Que el sistema deje de esperar cuando se supera ese tiempo.
  • Que se informe un error adecuado.
  • Que el estado interno quede consistente.
  • Que se registre información útil para diagnóstico.

Los timeouts deben ser razonables para el ambiente de prueba: ni tan largos que vuelvan lenta la suite, ni tan cortos que generen falsos fallos.

22.5 Reintentos

Un reintento es una nueva ejecución de una operación después de una falla. Puede ser útil para errores temporales, pero peligroso si se aplica sin criterio.

Conviene probar:

  • Cuántos reintentos se realizan.
  • Qué errores habilitan reintento.
  • Qué errores no deben reintentarse.
  • Qué ocurre cuando un reintento finalmente funciona.
  • Qué ocurre cuando todos los reintentos fallan.

Reintentar una operación inválida muchas veces solo agrega ruido. Reintentar una operación sensible sin idempotencia puede duplicar efectos.

22.6 Idempotencia y reintentos seguros

La idempotencia permite que una operación se repita sin generar efectos duplicados no deseados. Es especialmente importante cuando hay reintentos automáticos.

Una prueba puede verificar que repetir una misma operación:

  • No cree dos órdenes para la misma solicitud.
  • No descuente stock dos veces.
  • No cobre dos veces un pago.
  • No publique eventos duplicados si el contrato lo prohíbe.
  • No cree registros duplicados de auditoría crítica.

Si una operación no es idempotente, la estrategia de reintentos debe ser mucho más cuidadosa.

22.7 Errores recuperables y no recuperables

No todos los errores permiten recuperación automática. Diferenciar errores recuperables y no recuperables ayuda a evitar reintentos inútiles.

Ejemplos de errores recuperables:

  • Timeout temporal.
  • Servicio momentáneamente no disponible.
  • Bloqueo transitorio de base de datos.
  • Falla temporal de red.

Ejemplos de errores no recuperables:

  • Datos inválidos.
  • Credencial incorrecta.
  • Contrato incompatible.
  • Permiso insuficiente.

22.8 Manejo de errores en bases de datos

Las bases de datos pueden fallar por restricciones, bloqueos, conexiones, timeouts o problemas de transacción.

Una prueba puede verificar qué ocurre cuando:

  • Se intenta guardar un duplicado.
  • Falta una relación obligatoria.
  • Una transacción falla a mitad de camino.
  • La conexión no está disponible.
  • Una consulta tarda demasiado.

El resultado esperado debe incluir respuesta adecuada y estado de datos consistente.

22.9 Manejo de errores en APIs externas

Las APIs externas pueden devolver errores esperados o inesperados. La aplicación debe traducir esos errores a decisiones internas claras.

Casos importantes:

  • Pago rechazado.
  • Servicio no disponible.
  • Credencial vencida.
  • Límite de llamadas alcanzado.
  • Respuesta con formato inválido.
  • Operación pendiente de confirmación.

Las pruebas deben verificar qué estado queda en nuestra aplicación después de cada respuesta.

22.10 Manejo de errores en procesos asíncronos

En procesos asíncronos, el error puede ocurrir después de que la operación inicial ya respondió. Por eso el diagnóstico y el estado final son especialmente importantes.

Conviene probar:

  • Mensaje inválido.
  • Consumidor que falla temporalmente.
  • Reintentos agotados.
  • Mensaje enviado a cola de errores.
  • Procesamiento duplicado.
  • Registro de causa de falla.

El sistema debe evitar que un mensaje problemático bloquee indefinidamente todo el procesamiento.

22.11 Degradación controlada

A veces una dependencia falla, pero el sistema puede continuar parcialmente. Esto se llama degradación controlada.

Ejemplos:

  • Si falla el servicio de recomendaciones, se muestran productos populares.
  • Si falla el envío de correo, la orden queda creada y la notificación queda pendiente.
  • Si falla un reporte secundario, la operación principal continúa.

Una prueba de integración debe verificar que esta degradación ocurra solo cuando la regla del negocio lo permite.

22.12 Registro y evidencia

Cuando una integración falla, el sistema debe dejar evidencia suficiente para investigar. Esto no significa mostrar detalles técnicos al usuario, sino registrar información útil para el equipo.

Conviene registrar:

  • Identificador de operación.
  • Dependencia que falló.
  • Tipo de error.
  • Cantidad de reintentos.
  • Tiempo de respuesta.
  • Estado final de la operación.

La prueba puede verificar que ciertos errores queden registrados sin exponer secretos o datos sensibles.

22.13 Evitar errores silenciosos

Un error silencioso ocurre cuando algo falla pero el sistema no informa ni registra adecuadamente el problema. Esto es peligroso porque puede dejar datos incorrectos sin señales visibles.

Ejemplos:

  • No se envía una notificación y nadie lo registra.
  • Una exportación falla, pero el proceso queda como exitoso.
  • Un pago queda pendiente, pero la orden se marca como pagada.
  • Una llamada externa falla y se ignora sin decisión de negocio.

Las pruebas de integración deben comprobar que las fallas importantes no desaparezcan sin evidencia.

22.14 Ejemplo: timeout en pagos

Supongamos una compra donde la pasarela de pagos no responde a tiempo. Una prueba de integración podría verificar:

Elemento Resultado esperado
Respuesta de la operación Indica que el pago no pudo confirmarse o queda pendiente.
Orden No queda como pagada si no hay confirmación.
Stock No se descuenta definitivamente si la compra no fue confirmada.
Reintentos Se ejecutan según la política configurada.
Registro Queda evidencia del timeout y del identificador de operación.

22.15 Ejemplo: error permanente

Si un servicio externo rechaza una solicitud por datos inválidos, reintentar no resolverá el problema. La prueba debería verificar que:

  • La operación se rechaza de forma clara.
  • No se realizan reintentos innecesarios.
  • Los datos no quedan parcialmente confirmados.
  • El error se registra con información útil.
  • El usuario o proceso recibe una respuesta acorde.

Distinguir errores permanentes de temporales evita comportamientos costosos y confusos.

22.16 Errores comunes

Al probar manejo de errores, timeouts y reintentos, suelen aparecer errores como:

  • Probar solo caminos exitosos.
  • Reintentar todos los errores sin distinguir su tipo.
  • No verificar el estado final después de una falla.
  • No probar duplicados producidos por reintentos.
  • Usar timeouts demasiado largos para pruebas automatizadas.
  • No registrar evidencia suficiente.
  • Ocultar errores importantes con mensajes genéricos.

22.17 Lista de verificación

Antes de confiar en una integración, conviene revisar:

  • ¿Se prueban errores temporales y permanentes?
  • ¿Existe timeout configurado?
  • ¿Los reintentos tienen límite?
  • ¿Las operaciones reintentadas son idempotentes o están protegidas?
  • ¿El estado final queda consistente después de una falla?
  • ¿Se registran datos suficientes para diagnóstico?
  • ¿La respuesta de error es clara para quien la debe interpretar?

22.18 Qué debes recordar de este tema

  • Las integraciones deben probarse también cuando las dependencias fallan.
  • Los timeouts evitan esperas indefinidas.
  • Los reintentos sirven para errores temporales, pero pueden duplicar efectos si no hay control.
  • La idempotencia es clave para reintentos seguros.
  • El estado final debe verificarse después de errores.
  • Un buen manejo de errores deja evidencia útil sin exponer información sensible.

22.19 Conclusión

El manejo de errores, timeouts y reintentos define la resiliencia de una integración. Una prueba de integración completa no se limita a confirmar que el camino exitoso funciona; también verifica qué ocurre cuando las dependencias fallan.

Probar estos escenarios ayuda a evitar datos inconsistentes, operaciones duplicadas, errores silenciosos y diagnósticos difíciles.

En el próximo tema veremos dobles de prueba en integración: stubs, fakes y servicios simulados.