La forma sigue a la función: cómo crear envíos de formularios resilientes a gran escala

La forma sigue a la función: cómo crear envíos de formularios resilientes a gran escala

Jake Byman
Ingeniero de software sénior, backend
Ver perfil del autor
Jake Byman
Ingeniero de software sénior, backend
Ver perfil del autor
Índice de contenidos

¡Estamos contratando!

Buscamos talento en producto e ingeniería para que se una a nuestra misión de poner superpoderes de desarrollo al alcance de todos.

→
↗
►
↓
←
↑

¡Estamos contratando!

Buscamos talento en producto e ingeniería para que se una a nuestra misión de poner superpoderes de desarrollo al alcance de todos.

→
↗
►
↓
←
↑

Durante los últimos meses, hemos estado invirtiendo activamente en la resiliencia de nuestra empresa. Esta entrada de blog explica cómo una de esas inversiones nos ayudó durante un incidente reciente en el que fallaron las operaciones de la base de datos.

Envíos de formularios

Webflow impulsa tanto a nuestros clientes como a los clientes de estos. Para muchas empresas, los embudos de ventas dependen de los envíos de formularios entrantes, por lo que la disponibilidad y durabilidad de esta función son fundamentales.

Un envío de formulario típico llega a la API de Webflow, pasa por controles de spam y se guarda en el sitio del cliente. Los clientes pueden ver y exportar estos envíos desde su panel de control de Webflow. A menudo, los clientes tienen configurados webhooks con estos formularios hacia sus propios sistemas internos, lo que les permite realizar acciones personalizadas con cada nuevo envío.

Objetivos de diseño

Nos propusimos garantizar que, incluso durante fallos en los sistemas secundarios, los envíos de formularios fueran:

  1. Duraderos: nunca se pierden, incluso si falla el guardado en la base de datos
  2. No bloqueantes: los mecanismos de recuperación no deben ralentizar la ruta crítica de la solicitud
  3. Idempotentes: seguros para volver a procesar sin crear duplicados
  4. Operables: fáciles de dirigir a un solo cliente o ejecutar en todo el sistema

Fase 1: Copias de seguridad con registro previo (Write-Ahead Backups)

La primera pregunta que debíamos hacernos era: ¿dónde deberían residir las copias de seguridad? Queríamos suficiente contexto para volver a procesar correctamente, sin añadir dependencias externas que pudieran fallar antes de que se registrara la copia de seguridad.

Optamos por colocar esto lo más arriba posible en la capa de la API, después de la validación básica del middleware, pero antes de realizar cualquier llamada a la base de datos. Al priorizar la disponibilidad de las copias de seguridad, decidimos almacenar copias de todos los envíos, incluso aquellos que luego se filtrarían como spam, así como los que se procesarían correctamente.

Decidimos usar Amazon S3 para almacenar estas copias de seguridad. Como en cualquier sistema distribuido, tuvimos que considerar qué sucedería si la solicitud de copia de seguridad fallaba y si debía ser una llamada de red bloqueante. La prioridad era servir el envío del formulario en la ruta crítica; proteger el tráfico en vivo tiene prioridad sobre el éxito de la copia de seguridad.

Fase 2: Reintento (Replay)

Con las copias de seguridad guardadas en disco, nos propusimos construir un sistema para volver a procesar los envíos de formularios en caso de una interrupción del servicio que impidiera guardarlos correctamente en la base de datos. Llamamos a este sistema replay. Esta operación debía ejecutarse en dos modos: reintento por cliente y reintento global.

Modo 1: Reintento por sitio

Este modo de reintento se ejecutaría en caso de que un solo sitio o un pequeño grupo de sitios necesitaran ser procesados nuevamente. Sería un enfoque más rápido y específico para solucionar una interrupción en el envío de formularios que afectara a un solo cliente.

Modo 2: Reintento global

Esta sería la forma más contundente de ejecutar la operación e implicaría recorrer las copias de seguridad de todos los clientes y volver a procesarlas de forma generalizada. Esta operación sería más lenta, pero se utilizaría ante una interrupción sistémica que afectara a una gran parte de los clientes.

Hashes de envío

Las interrupciones rara vez provocan el fallo del 100% de las solicitudes. Un patrón típico se ve así:

✅✅⛔✅⛔⛔✅⛔⛔⛔⛔✅

Donde ✅ representa un envío procesado correctamente y ⛔ uno que falló antes de guardarse en la base de datos. Queríamos asegurarnos de que, al repetir el proceso de principio a fin, no duplicáramos los envíos de formularios marcados con ✅ que ya habían sido procesados.

Para lograrlo, decidimos implementar un concepto llamado hashes de envío. Cada envío de formulario se representa como un hash único y estable, donde el hash SHA-256 engloba todo lo que hace que ese envío sea único: la marca de tiempo en la que entró al sistema, los datos del cliente, el cuerpo del formulario, los metadatos de la solicitud y más. Estos hashes se serializan en la ruta crítica de cada envío de formulario, independientemente del contexto de repetición.

También almacenamos y añadimos un índice de base de datos en este campo, de modo que pudiéramos consultar de forma eficiente los envíos por su hash para determinar si ya habían sido procesados con éxito.

Esto significa que, al eliminar duplicados mediante hashes de envío, pudimos crear un proceso de repetición idempotente. Así, podíamos repetir envíos en un rango amplio y asegurar que la única diferencia fueran aquellos que no se procesaron correctamente la primera vez. Además, al elegir la ventana de tiempo para la repetición, podíamos seleccionar con total tranquilidad marcas de tiempo muy anteriores y posteriores a la interrupción, garantizando que cubríamos todo el rango sin preocuparnos por procesar registros que ya estaban guardados.

const isDuplicate = await checkIfDuplicateFormSubmission({
   siteId,
   workspace,
   body,
   createdOn,
});

if (isDuplicate) {
   return;
}

Pruebas de caos

Además de las pruebas unitarias y de integración, necesitábamos simular una interrupción real para comprobar que esta herramienta funcionaba. Para ello, realizamos una prueba en nuestro entorno de pruebas (staging) donde rompimos deliberadamente los envíos de formularios. Lo hicimos lanzando una excepción no controlada en la ruta de ingesta, simulando una interrupción estándar.

Luego, intentamos realizar varios envíos que, como esperábamos, no se procesaron correctamente. Después, desplegamos una versión que corregía el entorno (simulando la reversión de un cambio problemático). Con eso, obtuvimos nuestro escenario de repetición: envíos de formularios que faltaban en la base de datos del cliente pero que estaban presentes en nuestras copias de seguridad.

A partir de ahí, ejecutamos el proceso de repetición. Primero, fuera del periodo de interrupción para confirmar que no pasaba nada. Luego, ejecutamos el proceso justo durante el periodo de interrupción para demostrar que podíamos recuperar los envíos perdidos. Después, realizamos una repetición que abarcaba tanto antes como después del periodo de interrupción, demostrando que solo se repetían los envíos faltantes. Por último, ejecutamos el proceso varias veces para probar que la operación era idempotente y que los hashes de envío eliminaban correctamente los duplicados.

Tras esto, tuvimos la confianza de que esta era una herramienta que podíamos usar en caso de incidente.

Consideraciones sobre el spam

Los formularios atraen spam. Utilizamos múltiples defensas en las capas de red y de aplicación. Una verificación en la capa de aplicación depende de un token descendente con un TTL (tiempo de vida) de 1 hora; durante incidentes prolongados, esa señal no es fiable. La repetición recurre a las otras capas, pero en la recuperación elegimos "más datos antes que menos", lo que significa que algo de spam adicional podría llegar a los clientes en ciertos escenarios de repetición.

Gestión de incidentes

Durante nuestro reciente incidente, nos encontramos en una situación donde este trabajo de resiliencia fue puesto a prueba. Las escrituras en la base de datos estaban fallando y necesitábamos evaluar si era necesario realizar tareas de repetición.

Para evaluarlo, revisamos nuestras métricas. Por lo general, debería haber un trabajo de respaldo por cada formulario almacenado; la proporción esperada durante el tráfico normal es aproximadamente 1:1. Sin embargo, en caso de una interrupción del servicio, las métricas mostrarían una brecha entre el volumen de respaldo y el volumen de envíos persistidos, lo que indicaría que había trabajo de repetición pendiente.

Teníamos un manual de procedimientos, monitores y la experiencia de haber hecho esto antes. Así que analizamos la situación y elaboramos un plan para ejecutar una operación de repetición global.

Form submissions vs. Form backup jobs

La magnitud del problema y la necesidad de la operación de repetición eran considerables, con varias horas de respaldos por procesar. Afortunadamente, la operación se desarrolló sin contratiempos, procesando millones de respaldos y enviando los formularios correctamente a nuestros clientes.

¿Qué sigue?

Todavía queda trabajo por hacer.

  1. Mover los respaldos aún más atrás en la pila para reducir las ventanas de fallo previas al respaldo. Filtrado de spam más inteligente durante la repetición y en la ruta crítica. Repetición más rápida y económica: tuberías de transmisión, contrapresión y particionamiento más granular para reducir el consumo de cómputo, manteniendo la idempotencia y resiliencia actuales.

Conclusión

Perder los datos de los formularios de los clientes es catastrófico. La resiliencia en esta área es fundamental para nuestros clientes, por lo que contar con sistemas para realizar la recuperación de datos es esencial. Igual de importante es tener un manual de procedimientos y la experiencia necesaria para ejecutar estos sistemas de forma segura. Nos tomamos las interrupciones del servicio muy en serio. Cuando ocurren, priorizamos una recuperación segura y verificable. En este incidente, recuperamos casi un millón de envíos de formularios respaldados y los entregamos a los destinatarios correctos.

¿Te apasiona crear sistemas distribuidos resilientes? Si es así, únete a nuestro equipo!

¡Estamos contratando!

Buscamos talento en producto e ingeniería para que se una a nuestra misión de poner superpoderes de desarrollo al alcance de todos.

→
↗
►
↓
←
↑
Leer ahora

Última actualización
September 9, 2025
Categoría

Artículos relacionados

Escalar con confianza: cómo Webflow gestiona el crecimiento y el rendimiento a gran escala
Escalar con confianza: cómo Webflow gestiona el crecimiento y el rendimiento a gran escala

Escalar con confianza: cómo Webflow gestiona el crecimiento y el rendimiento a gran escala

Escalar con confianza: cómo Webflow gestiona el crecimiento y el rendimiento a gran escala

Ingeniería
Por
Allan Leinwand
,
,
Leer artículo
Seguridad desde el diseño, rapidez por defecto: cómo usamos la automatización para escalar SCA en Webflow
Seguridad desde el diseño, rapidez por defecto: cómo usamos la automatización para escalar SCA en Webflow

Seguridad desde el diseño, rapidez por defecto: cómo usamos la automatización para escalar SCA en Webflow

Seguridad desde el diseño, rapidez por defecto: cómo usamos la automatización para escalar SCA en Webflow

Ingeniería
Por
Marcelo Sacchetin
,
,
Leer artículo
Cómo crear un plan de recuperación ante desastres (DRP) para sitios web: guía de 5 pasos para reducir el tiempo de inactividad
Cómo crear un plan de recuperación ante desastres (DRP) para sitios web: guía de 5 pasos para reducir el tiempo de inactividad

Cómo crear un plan de recuperación ante desastres (DRP) para sitios web: guía de 5 pasos para reducir el tiempo de inactividad

Cómo crear un plan de recuperación ante desastres (DRP) para sitios web: guía de 5 pasos para reducir el tiempo de inactividad

Estrategia
Por
Vinamrata Singal
,
,
Leer artículo
Construir con IA: cómo los ingenieros de Webflow avanzan más rápido, piensan más a fondo y lanzan productos de forma más inteligente
Construir con IA: cómo los ingenieros de Webflow avanzan más rápido, piensan más a fondo y lanzan productos de forma más inteligente

Construir con IA: cómo los ingenieros de Webflow avanzan más rápido, piensan más a fondo y lanzan productos de forma más inteligente

Construir con IA: cómo los ingenieros de Webflow avanzan más rápido, piensan más a fondo y lanzan productos de forma más inteligente

Ingeniería
Por
Allan Leinwand
,
,
Leer artículo
Los elementos esenciales de un stack tecnológico empresarial
Los elementos esenciales de un stack tecnológico empresarial

Los elementos esenciales de un stack tecnológico empresarial

Los elementos esenciales de un stack tecnológico empresarial

Estrategia
Por
Equipo de Webflow
,
,
Leer artículo
Cómo el desarrollo visual ayuda a las empresas a escalar sus negocios
Cómo el desarrollo visual ayuda a las empresas a escalar sus negocios

Cómo el desarrollo visual ayuda a las empresas a escalar sus negocios

Cómo el desarrollo visual ayuda a las empresas a escalar sus negocios

Estrategia
Por
Mischa Vaughn
,
,
Leer artículo

verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logoreddit logothe new york times logoideo logoupwork logodiscord logo
verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logoreddit logothe new york times logoideo logoupwork logodiscord logo

Empieza gratis

Prueba Webflow todo el tiempo que quieras con nuestro plan Starter gratuito. Compra un plan de sitio de pago para publicar, alojar y desbloquear funciones adicionales.

Empieza, es gratis
Ver demostración

Prueba Webflow todo el tiempo que quieras con nuestro plan Starter gratuito. Compra un plan de sitio de pago para publicar, alojar y desbloquear funciones adicionales.