Saltar al contenido

Lección 13 de 20 · Lectura y práctica

Manejar errores y timeouts con códigos de estado gRPC

Tipo de lección: VideoConcepto claveEn sistemas distribuidos, los errores y timeouts no son excepciones sino eventos esperados. gRPC utiliza códigos de estado específicos para categorizar estos eventos, permitiendo un manejo.

Del concepto a la práctica

Taller de esta lección

Los estados gRPC deben expresar la causa operativa y guiar la reacción del cliente. Un argumento inválido no mejora con reintentos; una dependencia no disponible puede reintentarse con límite; un deadline agotado exige abandonar el trabajo asociado.

Ejemplo resuelto

text
sku vacío                 -> INVALID_ARGUMENT -> corregir entrada
inventario temporalmente caído -> UNAVAILABLE -> reintento acotado
límite de 50 ms agotado   -> DEADLINE_EXCEEDED -> cancelar

La etiqueta y la acción forman una sola decisión de diseño.

En una mutación, DEADLINE_EXCEEDED no demuestra que la operación no se aplicó: la respuesta puede perderse tras el commit. Reconcilia mediante ID de operación y diseña idempotencia antes de reintentar. El trabajo de la aplicación debe cooperar con la cancelación; gRPC no mata una tarea arbitraria. Propaga a dependencias el presupuesto restante, no reinicies el plazo completo en cada salto.

Pruébalo

  1. Simula cada causa en un servicio local.

  2. Asigna un estado y una acción cliente por caso.

  3. Limita los reintentos y registra el intento final.

Error frecuente: reintentar todos los errores automáticamente. Corrección: reintenta solo fallos transitorios y evita duplicar operaciones no idempotentes.

Comprueba tu resultado

Ejercicio: procesa los tres casos anteriores. Resultado esperado: cero reintentos para entrada inválida, una política limitada para disponibilidad y cancelación al superar 50 ms.

Capas de acceso, actualización, copias y respuesta a incidentes alrededor de un sistema.
CursaloMapa de práctica
La seguridad necesita varias capas

El control de acceso, las actualizaciones y las copias de seguridad cubren riesgos distintos. Una alerta necesita un procedimiento de respuesta para contener y recuperar el servicio. Varias capas reducen la exposición, pero ninguna garantiza seguridad absoluta.

Ver la infografía en tamaño completo ↗

Tipo de lección: Video

Concepto clave

En sistemas distribuidos, los errores y timeouts no son excepciones sino eventos esperados. gRPC utiliza códigos de estado específicos para categorizar estos eventos, permitiendo un manejo estructurado que va más allá del simple "éxito/fracaso". Imagina un sistema de mensajería entre oficinas: no es lo mismo que un mensaje se pierda (DEADLINE_EXCEEDED) a que el destinatario esté ocupado (UNAVAILABLE) o que el mensaje sea ilegible (INVALID_ARGUMENT).

Los códigos de estado gRPC se dividen en cuatro categorías principales: OK (éxito), errores de cliente (4xx equivalentes), errores de servidor (5xx equivalentes) y errores de red/tiempo. La clave en producción es que cada código debe desencadenar una estrategia de recuperación específica, como retry con backoff exponencial para UNAVAILABLE, pero no para INVALID_ARGUMENT.

Cómo funciona en la práctica

Implementar un manejo robusto requiere configurar tanto el cliente como el servidor. En el servidor, debes devolver códigos específicos usando excepciones o respuestas de error. En el cliente, debes interceptar estos códigos y decidir la acción.

Ejemplo básico en Go:

// Servidor: Devolver error con código específico
status.Error(codes.DeadlineExceeded, "Timeout procesando solicitud")

// Cliente: Manejar el error
err := client.CallRPC(ctx, request)
if err != nil {
    st, ok := status.FromError(err)
    if ok {
        switch st.Code() {
        case codes.DeadlineExceeded:
            // Loggear y posiblemente retry con contexto renovado
        case codes.ResourceExhausted:
            // Implementar circuit breaker
        default:
            // Manejo genérico
        }
    }
}

Configurar timeouts es crítico: usa context.WithTimeout en el cliente y verifica ctx.Err() en el servidor para abortar operaciones largas.

Caso de estudio

Sistema de pagos en e-commerce con microservicios: Servicio de Ordenes llama a Servicio de Pagos. Durante Black Friday, el servicio de pagos sufre alta carga.

EscenarioCódigo gRPCAcción en ClienteImpacto Usuario
Pago procesado exitosamenteOKConfirmar ordenOrden completada
Timeout de 2 segundos excedidoDEADLINE_EXCEEDEDRetry 1 vez con nuevo timeout de 5sLigera demora
Servicio de pagos caídoUNAVAILABLECircuit breaker abre, fallback a cacheMensaje "Reintentar más tarde"
Tarjeta inválidaINVALID_ARGUMENTMostrar error inmediatoCorregir datos
En producción, monitorea la distribución de códigos de estado: más del 1% de DEADLINE_EXCEEDED puede indicar necesidad de escalar o optimizar.

Errores comunes

  • Usar timeouts genéricos: No aplicar timeouts específicos por operación. Solución: Define timeouts basados en percentiles P99 de latencia histórica.
  • Ignorar códigos de estado: Tratar todos los errores igual. Solución: Implementar lógica de recuperación diferenciada por código.
  • Retry infinito: Reintentar en errores no retryables como INVALID_ARGUMENT. Solución: Usar bibliotecas como retry-go con políticas configuradas.
  • No propagar contextos: Perder información de deadline en llamadas anidadas. Solución: Pasar siempre el contexto original o derivado.
  • Falta de circuit breakers: Continuar llamando a servicios caídos. Solución: Integrar patrones como hystrix o resilience4j.

Checklist de dominio

  1. ¿Configuras timeouts diferentes para operaciones de lectura vs escritura?
  2. ¿Tu cliente distingue entre errores retryables y no retryables?
  3. ¿Implementas backoff exponencial con jitter para retries?
  4. ¿Monitoreas la tasa de códigos DEADLINE_EXCEEDED por servicio?
  5. ¿Usas circuit breakers para servicios críticos?
  6. ¿Propagas contextos correctamente en toda la cadena de llamadas?
  7. ¿Tienes fallbacks definidos para cuando los servicios están UNAVAILABLE?

Implementar cliente resiliente con retry y circuit breaker

En este ejercicio, mejorarás un cliente gRPC básico para que maneje errores de producción reales.

  1. Configura el entorno: Clona el repositorio con un servicio de simulación que devuelve errores aleatorios (UNAVAILABLE, DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED).
  2. Implementa retry inteligente: Modifica el cliente para reintentar solo en códigos retryables (UNAVAILABLE, DEADLINE_EXCEEDED) con backoff exponencial: 100ms, 200ms, 400ms, máximo 3 intentos.
  3. Añade circuit breaker: Configura un circuit breaker que se abra después de 5 fallos consecutivos y se cierre tras 30 segundos. Usa la biblioteca "goresilience" o similar.
  4. Simula carga: Ejecuta 1000 llamadas concurrentes y registra: éxitos, fallos por tipo de error, y activaciones del circuit breaker.
  5. Optimiza: Ajusta los timeouts basado en los resultados: si más del 5% son DEADLINE_EXCEEDED, aumenta el timeout inicial.
Pistas
  • Usa status.FromError() para obtener el código gRPC del error.
  • Para el circuit breaker, considera implementar un patrón de estado (closed, open, half-open).
  • Prueba con diferentes tasas de error en el servicio simulado para ver cómo se comporta tu cliente.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con Implementación Avanzada de gRPC y Protocol Buffers para Microservicios

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.