Cuando dos sistemas necesitan mantenerse sincronizados hay que decidir quién inicia el intercambio: el sistema externo puede avisar mediante webhooks o el nuestro puede consultar cambios mediante polling. Las dos estrategias funcionan. Las dos tienen ventajas. Y las dos pueden convertirse en un problema si se eligen por costumbre. No importa cuál parece más moderna. Importa cuál se adapta mejor al tipo de dato que estamos moviendo.
Esta decisión suele ser parte de una integración API más amplia, donde también hay que definir qué sistema manda y cómo recuperar los fallos.
Qué hace un webhook
Un webhook permite que un sistema avise a otro cuando ocurre algo. Se creó un pedido. Cambió un cliente. Se completó un pago.
Se actualizó un producto. En lugar de consultar constantemente si hubo cambios, esperamos a que el sistema origen envíe una notificación. Eso puede hacer que la sincronización sea casi inmediata y evita muchas consultas innecesarias. En el caso ideal, el flujo es simple: ocurre algo → llega el webhook → procesamos el cambio. El problema es que el caso ideal no siempre es el caso real.
Qué hace el polling
Con polling hacemos lo contrario: nuestro sistema consulta periódicamente al otro si hay algo nuevo. El intervalo puede ser de un minuto, cinco minutos o una hora, según cuánto pueda esperar la información. Una implementación básica consulta los registros modificados desde la última sincronización y procesa solamente esos cambios.
Es menos inmediato que un webhook, pero tiene una ventaja importante:
somos nosotros quienes controlamos cuándo ocurre la sincronización.
Tiempo real no siempre significa mejor
Supongamos que estamos sincronizando precios entre dos sistemas. Que una demora de tres minutos afecte al negocio depende del uso de esos precios; no puede decidirse desde la arquitectura solamente.
Si no cambia nada importante, una sincronización periódica puede ser mucho más sencilla de operar que una infraestructura basada en eventos. Ahora pensemos en un pago. Cuando el proveedor confirma que una transacción fue aprobada, probablemente queramos procesar esa información lo antes posible.
Ahí un webhook tiene mucho más sentido. La velocidad necesaria debería salir del problema. No de la arquitectura.
Los webhooks pueden perderse
Un webhook es una petición HTTP. Y las peticiones HTTP pueden fallar. Nuestro servidor puede estar caído. Puede responder demasiado lento.
Puede haber un problema temporal de red. El proveedor puede tener una interrupción. Por eso una integración seria no debería asumir que cada webhook va a llegar exactamente una vez. Algunos servicios reintentan automáticamente.
Otros hacen pocos intentos. Otros directamente no garantizan demasiado. Hay que saber qué comportamiento tiene el proveedor con el que estamos trabajando.
También pueden llegar dos veces
Esto es bastante normal. El servicio envía un webhook. Lo procesamos correctamente. Pero nuestra respuesta tarda más de lo esperado.
El proveedor interpreta que hubo un problema y vuelve a enviarlo. Si nuestro código simplemente ejecuta la operación otra vez, podemos duplicar pedidos, pagos, emails, registros o procesos internos. Por eso un webhook debería poder procesarse de forma idempotente. La idempotencia, el orden y los reintentos también forman parte del diseño general de una integración de API fuera del caso feliz.
Si el mismo evento llega dos veces, el resultado debería ser el mismo que si hubiera llegado una sola.
Y pueden llegar desordenados
Imaginemos estos eventos:
- Pedido creado
- Pedido pagado
- Pedido cancelado
No deberíamos asumir que necesariamente van a llegar en ese orden. Por latencia, reintentos o procesamiento interno del proveedor, podríamos recibir primero el tercero y después el segundo. Si aplicamos cada evento ciegamente, podemos terminar reconstruyendo un estado que nunca existió. A veces conviene usar el webhook solamente como aviso:
algo cambió.
Y después consultar el objeto actual directamente desde la API. Eso agrega una petición, pero puede simplificar bastante el manejo de estados.
Polling es simple, pero puede ser caro
Consultar una API cada minuto parece sencillo. El enfoque se complica cuando aparecen cien mil productos, límites de solicitudes, varios clientes y muchos procesos sincronizando a la vez. Si en cada ejecución descargamos todo para encontrar cinco cambios, estamos haciendo mucho trabajo innecesario. El polling funciona mejor cuando la API permite preguntar por cambios incrementales.
Por ejemplo:
Entre los mecanismos útiles están updated_since, los cursores, las fechas de modificación, las páginas ordenadas y los identificadores crecientes. La idea es consultar solamente lo que pudo haber cambiado.
La frecuencia tiene que tener una razón
Es común encontrar procesos ejecutándose cada minuto simplemente porque alguien eligió ese intervalo al desarrollarlos. Pero el intervalo de sincronización debería equilibrar cuánto puede esperar el negocio con el costo de cada ejecución.
El inventario de una tienda puede necesitar actualizarse bastante seguido. Un catálogo que cambia una vez por semana probablemente no. Una integración no mejora porque ejecute más veces. Mejora cuando los datos llegan dentro del tiempo en que siguen siendo útiles.
A veces conviene usar los dos
Webhooks y polling no son necesariamente alternativas excluyentes. Una estrategia bastante robusta puede usar webhooks para reaccionar rápidamente y polling como mecanismo de reconciliación. El webhook nos avisa casi en tiempo real. Cada cierto período, además, revisamos si existe algún cambio que por alguna razón no llegó.
Eso permite aprovechar la velocidad de los eventos sin confiar completamente en que ninguna notificación se va a perder. Para datos importantes puede valer la pena.
Hay que pensar en la caída del sistema externo
Con polling, si la API externa no responde, podemos registrar el error y volver a intentar después. Con webhooks aparece otra pregunta. ¿Qué ocurre si nuestro sistema está caído durante veinte minutos? ¿El proveedor guarda los eventos?
Necesitamos saber si el proveedor reenvía los eventos, durante cuánto tiempo y si existe una API para recuperar lo ocurrido durante ese período. Sin esas respuestas queda un agujero en la integración.
La arquitectura debería contemplar cómo recuperar el estado después de una interrupción.
Seguridad también cambia
Un proceso de polling normalmente inicia la conexión desde nuestro sistema hacia una API autenticada. Un webhook hace lo contrario. Estamos exponiendo un endpoint para que otro sistema nos llame. Eso significa que necesitamos verificar que la petición realmente venga del proveedor esperado.
Muchos servicios firman sus webhooks mediante un secreto compartido. Nuestro endpoint puede validar esa firma antes de procesar el contenido. No alcanza con que alguien conozca la URL. Un webhook es una entrada al sistema y debería tratarse como tal.
No procesar todo dentro del webhook
Otra decisión útil es responder rápido. Cuando llega un webhook, podemos validar la petición, guardar el evento y devolver una respuesta satisfactoria. El trabajo pesado puede ejecutarse después mediante una cola o un proceso en segundo plano. Eso reduce el riesgo de que el proveedor interprete que la petición falló porque tardamos demasiado.
También permite controlar mejor los reintentos y la carga. El webhook comunica el evento y el sistema lo procesa, pero ambas tareas no tienen que ocurrir en la misma petición.
Qué elegir
Si el cambio necesita reflejarse rápidamente y el proveedor tiene un sistema de webhooks confiable, probablemente empezaría por ahí. Si algunos minutos de demora son aceptables y la API permite consultar cambios eficientemente, polling puede ser mucho más simple. Si los datos son críticos, quizá tenga sentido combinar ambos.
Y si todavía no sabemos cuánto importa la latencia, probablemente no necesitemos empezar por la opción más compleja.
La arquitectura tiene que seguir al dato
Webhooks y polling son mecanismos. No son decisiones de producto por sí mismos. La pregunta real es: ¿qué pasa si este dato tarda cinco minutos?
¿qué pasa si perdemos un evento? ¿podemos reconstruir el estado? ¿cuánto volumen vamos a procesar? ¿quién controla el sistema externo?
Con esas respuestas, la elección suele volverse bastante menos misteriosa. La decisión queda bastante acotada cuando conocemos la latencia tolerable, el costo de consulta y cómo reconstruir el estado. No todo necesita tiempo real; cada dato necesita llegar dentro de su ventana útil.