saltar al contenido
volver al mapa
práctica
etapa: escalar
3 min de lectura

Confiabilidad a escala: idempotencia, reintentos y backpressure

En los sistemas distribuidos todo falla en algún momento. Lo que distingue a una plataforma de seguridad confiable es cómo se comporta cuando eso ocurre: sin perder eventos y sin actuar dos veces.

RedisTemporalEnvoyPrometheus

Qué es

Aquí la confiabilidad es la propiedad de seguir siendo correcto bajo fallas: una red que se cae, una dependencia lenta, un mensaje repetido, un pico de volumen. En seguridad las dos fallas más costosas son perder un evento (una detección que nunca se dispara) y actuar dos veces (bloquear, notificar o revocar por duplicado).

El enfoque práctico es aceptar que la entrega será at-least-once y hacer idempotente el procesamiento, en lugar de perseguir una entrega "exactly-once" mágica de punta a punta.

Idempotencia: reprocesar sin efecto adicional

Una operación es idempotente cuando ejecutarla varias veces da el mismo resultado que ejecutarla una sola vez. Para los eventos, el camino habitual es darle a cada uno un identificador estable y registrar los ya procesados: si el ID reaparece, el handler lo descarta o repite solo lo que es seguro.

  • ID de evento determinista (hash de los campos relevantes, o el ID del origen) para detectar repeticiones.
  • Registro de los IDs procesados con plazo (Redis con expiración, o una tabla con restricción de unicidad).
  • Acciones definidas por estado deseado ("la IP X está bloqueada hasta T") en lugar de acciones incrementales ("bloquea"), ya que repetir el estado deseado no cambia nada.

Reintentos con backoff y jitter

Reintentar una llamada que falló ayuda, pero reintentar todo al mismo tiempo tumba la dependencia que acaba de recuperarse. El patrón estándar es el backoff exponencial (esperar más en cada intento) con jitter (aleatoriedad para desincronizar a los clientes) y un tope de intentos, tras el cual el evento va a la .

retry.pypython
import random
import time


def retry(fn, max_attempts=5, base=0.2):
    for i in range(max_attempts):
        try:
            return fn()
        except Exception as err:
            if i == max_attempts - 1:
                raise RuntimeError(f"se agotaron los {max_attempts} intentos") from err
            # backoff exponencial con jitter total: espera en [0, base * 2**i)
            time.sleep(random.uniform(0, base * 2 ** i))

Backpressure y aislamiento

  • Backpressure: colas y buffers con límite. Cuando el consumidor no da abasto, el productor desacelera o el exceso se descarta de forma deliberada, en lugar de que la memoria crezca hasta que el proceso muere.
  • Circuit breaker: tras fallas consecutivas, dejar de llamar a la dependencia por un tiempo y responder con un fallback definido.
  • Bulkheads: pools separados por dependencia, para que la lentitud de una no consuma los recursos de todas.
  • Timeouts en toda llamada externa, con un plazo menor que el del llamador.

Fallar de forma segura

Cada componente necesita una respuesta definida para "no pude decidir". Un enriquecimiento que falló debe generar el evento sin el campo (y una marca de que faltó), no descartarlo. Una acción automática que no pudo confirmar el contexto debe pedir aprobación humana, no actuar a ciegas.

DLQdead letter queueCola para los eventos que no pudieron procesarse tras los reintentos. Evita bloquear el flujo y conserva el evento para su análisis.ver en el glosario →

conexiones en el mapa

actualizado el 14/10/2026 · fuentes para profundizar · reportar un error

en otros dominios

Estudia antes

Desbloquea

pon a prueba lo que entendiste

Cargando preguntas…