Versionado de Eventos
Cómo evolucionar schemas de eventos en sistemas event-driven — compatibilidad backward/forward, upcasting y schema registry.
El desafío del versionado de eventos
En una arquitectura event-driven, los eventos son el contrato entre productores y consumidores. A diferencia de las APIs REST donde el consumidor hace un request y recibe una respuesta inmediata, los eventos se publican y pueden ser consumidos por múltiples servicios — incluso servicios que no existían cuando el evento fue definido.
Esto hace que el versionado de eventos sea más complejo que el de APIs: no podés simplemente “deprecar” un evento porque puede haber consumidores que reprocesan eventos históricos del log.
Evolución de schemas
Cambios compatibles (safe changes)
Estos cambios no rompen consumidores existentes:
- Agregar campos opcionales: Los consumidores que no conocen el campo lo ignoran
- Agregar nuevos tipos de eventos: Los consumidores que no los reconocen los descartan
- Ampliar rangos de valores: Por ejemplo, aceptar más valores en un enum (si los consumidores manejan valores desconocidos)
Cambios incompatibles (breaking changes)
Estos cambios requieren una estrategia de migración:
- Eliminar campos: Consumidores que dependen del campo fallarán
- Renombrar campos: Equivalente a eliminar uno y agregar otro
- Cambiar tipos de datos: Un consumidor que espera un string y recibe un number fallará
- Cambiar la semántica: El campo existe pero significa algo diferente
Compatibilidad backward y forward
Backward compatibility (lectores nuevos, escritores viejos)
Un schema es backward compatible si los consumidores con el schema nuevo pueden leer eventos producidos con el schema viejo. Esto se logra cuando:
- Los campos nuevos tienen valores por defecto
- No se eliminan campos que los consumidores nuevos esperan
Forward compatibility (lectores viejos, escritores nuevos)
Un schema es forward compatible si los consumidores con el schema viejo pueden leer eventos producidos con el schema nuevo. Esto se logra cuando:
- Los consumidores ignoran campos desconocidos
- No se cambian los tipos de campos existentes
Full compatibility
Un schema es fully compatible cuando es tanto backward como forward compatible. Este es el nivel más seguro y el recomendado para la mayoría de los casos.
Event upcasting
El upcasting es una técnica para transformar eventos de una versión antigua a una versión nueva en tiempo de lectura. En lugar de migrar todos los eventos almacenados, se aplica una transformación cuando se leen:
Evento v1 almacenado → Upcaster v1→v2 → Consumidor recibe formato v2
Cómo funciona
- Los eventos se almacenan en su formato original (inmutables)
- Al leer, se aplica una cadena de upcasters según la versión del evento
- El consumidor siempre recibe el formato más reciente
Ventajas del upcasting
- No requiere migración masiva de datos
- Los eventos originales se preservan (audit trail intacto)
- Se pueden agregar nuevas transformaciones incrementalmente
Consideraciones
- La cadena de upcasters puede crecer con el tiempo (v1→v2→v3→v4)
- Cada upcaster debe ser determinista y sin efectos secundarios
- Conviene testear la cadena completa de transformaciones
Schema Registry
Un Schema Registry es un servicio centralizado que almacena y gestiona los schemas de todos los eventos del sistema. Herramientas como Confluent Schema Registry o AWS Glue Schema Registry ofrecen:
Funcionalidades clave
- Almacenamiento centralizado: Todos los schemas en un solo lugar
- Validación de compatibilidad: Rechaza schemas nuevos que rompan la compatibilidad configurada
- Evolución controlada: Permite definir reglas de compatibilidad por topic/tipo de evento
- Serialización/deserialización: Los productores y consumidores usan el registry para serializar y deserializar eventos
Niveles de compatibilidad configurables
| Nivel | Descripción |
|---|---|
| BACKWARD | Consumidores nuevos pueden leer eventos viejos |
| FORWARD | Consumidores viejos pueden leer eventos nuevos |
| FULL | Backward + Forward |
| NONE | Sin validación de compatibilidad |
Flujo típico
- El productor registra un schema nuevo en el registry
- El registry valida la compatibilidad con la versión anterior
- Si es compatible, asigna un ID al schema
- El productor serializa el evento con el schema ID
- El consumidor usa el schema ID para deserializar
Buenas prácticas
- Incluí siempre un campo de versión en tus eventos (
schemaVersion,eventVersion) - Usá formatos que soporten evolución — Avro, Protobuf o JSON Schema con reglas claras
- Configurá compatibilidad FULL como default en tu schema registry
- Diseñá consumidores tolerantes — que ignoren campos desconocidos y manejen campos faltantes con defaults
- Testeá la compatibilidad antes de deployar cambios de schema — idealmente en el pipeline de CI/CD
- Documentá cada versión del schema con su changelog y fecha de introducción