Modelo de Ejecución
El modelo de ejecución define cómo Asset Core procesa los cambios de estado y atiende consultas con garantías deterministas y auditables. Es la columna vertebral conceptual para cada API, SDK y flujo de trabajo operativo que encontrarás en otros lugares de la documentación.
Problema que este concepto resuelve
Los sistemas distribuidos enfrentan una tensión fundamental entre consistencia, disponibilidad y tolerancia a particiones. Los enfoques tradicionales a menudo sacrifican uno para lograr los otros, lo que lleva a problemas que son difíciles de depurar y aún más difíciles de reproducir. En los sistemas espaciales, estas fallas se manifiestan como posiciones incorrectas, actualizaciones en conflicto y deriva de estado irrecuperable.
- Condiciones de carrera cuando múltiples escritores actualizan el mismo estado
- Actualizaciones perdidas cuando los cambios concurrentes se sobrescriben entre sí
- Comportamiento no determinista que dificulta la depuración y la auditoría
- Protocolos de consenso costosos que añaden latencia y complejidad
Asset Core resuelve estos problemas al adoptar una arquitectura de escritor único con almacenamiento de eventos, intercambiando la escalabilidad horizontal de escritura por un determinismo absoluto y simplicidad. A través de espacios de nombres, esa compensación aún escala horizontalmente sin comprometer el contrato.
Ideas principales
Mundo de Escritor Único
Cada mundo tiene exactamente un escritor. Esta es la elección arquitectónica que hace posible todo lo demás.
En sistemas distribuidos, múltiples escritores requieren coordinación: bloqueos distribuidos, protocolos de consenso (Raft, Paxos) o consistencia eventual con resolución de conflictos. Cada enfoque intercambia algo valioso—ya sea latencia (bloqueo/consenso) o determinismo (consistencia eventual). Al depurar un incidente en producción, “consistente eventualmente” significa “podría ser inconsistente en este momento, buena suerte.”
El escritor único elimina toda esta clase de problemas:
-
Sin sobrecarga de coordinación: Un escritor significa sin bloqueos distribuidos, sin compromiso en dos fases, sin sobrecarga de protocolo de consenso. Las transiciones de estado son instantáneas y locales.
-
Sin condiciones de carrera: Cuando solo un proceso muta el estado, las operaciones se ejecutan en un orden total. Puedes razonar sobre causa y efecto de manera lineal. La depuración se convierte en un análisis forense, no en una conjetura probabilística.
-
Impuesto de protocolo sin consenso: Raft y Paxos añaden 2-3 veces de latencia y una complejidad sustancial. El comercio de un solo escritor intercambia la escalabilidad horizontal de escritura por simplicidad y velocidad.
El compromiso es real: no puedes escalar el rendimiento de escritura horizontalmente dentro de un solo mundo. El daemon de escritura serializa todos los commits a través de un solo pipeline, lo que limita el rendimiento de escritura a lo que un nodo puede manejar. Pero AssetCore hace que ese compromiso sea explícito y recupera la escalabilidad a través de la fragmentación de espacios de nombres: cada espacio de nombres es un mundo aislado de un solo escritor. En la práctica, el rendimiento se escala horizontalmente mediante la fragmentación entre espacios de nombres. Esto convierte el determinismo en una elección de diseño en lugar de una propiedad accidental.
Registro de Commits como Fuente de Verdad
Todos los cambios de estado se registran como eventos en un registro de confirmaciones de solo anexado:
- Los eventos están sellados en lotes antes de la confirmación
- Los lotes son agregados antes de que los clientes reciban respuestas de éxito (la durabilidad depende del backend)
- El registro es el documento autoritativo de todo lo que sucedió
Esta elección de diseño—tratar el registro como la fuente autorizada—tiene profundas implicaciones. Significa que las proyecciones son desechables: si pierdes el estado de lectura, vuelve a reproducir desde el registro. Significa que la analítica y las notificaciones nunca pueden desviarse de la fuente de verdad porque consumen el mismo registro. Significa que la depuración forense se convierte en un viaje en el tiempo: reproduce el registro hasta cualquier punto e inspecciona el estado exacto. El backend es enchufable, por lo que puedes ejecutar en memoria para simulaciones/pruebas (rápido, no duradero) o usar backends de archivos/segmentados para la persistencia en caso de fallos; la interfaz está diseñada para acomodar backends adicionales según sea necesario.
Sin esto, mantendría almacenes operativos y analíticos separados, lucharía contra la deriva de sincronización y perdería la capacidad de responder de manera definitiva “¿cuál era el estado a las 3:47 PM del martes cuando ocurrió el error?” El registro de confirmaciones hace que esa pregunta sea trivial. Este diseño permite la reproducción determinista: dado la misma secuencia de eventos, cualquier lector reconstruirá el mismo estado. También garantiza que los análisis, notificaciones y proyecciones siempre se deriven de la misma fuente de verdad.
Proyecciones
Las proyecciones son vistas optimizadas para lectura del estado derivadas del registro de confirmaciones:
- El daemon monitorea el registro de confirmaciones en busca de nuevos lotes
- Los eventos se aplican a través de la reproducción para actualizar el estado en memoria
- Las instantáneas se publican de manera atómica para el servicio de consultas
Las proyecciones son eventualmente consistentes con el registro de confirmaciones. La brecha entre los eventos confirmados y las proyecciones publicadas es el retraso de frescura, que se mide y se expone a través de los puntos finales de lectura.
Arquitectura de Tres Capas
La ejecución separa las preocupaciones en tres capas. Esta no es una abstracción arbitraria; es la forma en que AssetCore logra tanto rendimiento como corrección.
Sin separación, cada operación mezclaría el acceso al almacenamiento, la validación de la lógica de negocio y la coordinación de transacciones en una función monolítica. Esto dificulta las pruebas (no se puede probar la validación sin almacenamiento), hace que la reproducción sea frágil (la lógica de negocio durante la reproducción arriesga el no determinismo) y hace que el rendimiento sea impredecible (no se puede optimizar la ruta caliente por separado de la ruta de validación).
Las tres capas de AssetCore te ofrecen:
| Capa | Responsabilidad | Comportamiento |
|---|---|---|
| L1 (Almacenamiento) | Mutaciones de datos en bruto | Sin validación, sin eventos |
| L2 (Operaciones) | Lógica de negocio | Valida precondiciones, emite eventos |
| L3 (Transacciones) | Coordinación | Registra deshacer, maneja repetición |
L1 (Storage) es la capa de rendimiento. Expone configuraciones simples: “establecer este saldo en N”, “colocar esta instancia en las coordenadas (x,y)”. Sin validación, sin eventos, solo mutación de estado. Esto es lo que utiliza la reproducción: aplicación de estado pura, rápida y determinista.
L2 (Operaciones) es la capa de corrección. Valida las precondiciones (“¿existe este contenedor?”, “¿hay espacio en esta posición?”), ejecuta la lógica de negocio y emite eventos que describen lo que ha cambiado. Aquí es donde residen tus reglas de dominio.
L3 (Transacciones) es la capa de coordinación. Registra los pasos de deshacer para cada operación para que las fallas puedan activar un retroceso. Gestiona el ciclo de vida del compromiso: ejecuta operaciones en secuencia, sella eventos en un lote, añade al registro de compromisos en el backend, devuelve éxito.
Esta separación asegura que:
- Reproducción rápida: los configuradores L1 están optimizados para rutas críticas, sin sobrecarga de validación
- Lógica de negocio testeable: L2 se puede probar sin infraestructura de almacenamiento
- Reversión atómica: El registro de deshacer L3 puede revertir cualquier secuencia de operaciones
El costo: más capas de abstracción. La ganancia: puedes reproducir miles de eventos por segundo porque L1 está desacoplado de la lógica de validación de L2.
Cómo encaja en el sistema
El modelo de ejecución da forma a cada aspecto de Asset Core:
Escribir Ruta:
- El cliente envía una solicitud de confirmación
- El daemon valida y ejecuta operaciones (L2/L3)
- Los eventos se sellan y se añaden al registro de commits del backend
- El cliente recibe éxito con el número de secuencia
Ruta de Lectura:
- Leer el registro de commits de los daemon tails
- Los eventos se reproducen a través de los setters de L1 (idempotentes)
- Las proyecciones se publican a través de un intercambio atómico
- Consultas leídas desde la proyección actual
Recuperación:
- Cargar punto de control (último estado conocido bueno)
- Repetir eventos desde la posición de punto de control
- Reanudar la operación normal
Invariantes clave y garantías
Determinismo
Dada la misma secuencia de eventos, la reproducción produce un estado idéntico en bytes. Esto es lo que hace posible la depuración de viajes en el tiempo, la recuperación ante desastres y la auditoría forense.
El determinismo es más complicado de lo que parece. La mayoría de los sistemas tienen fuentes ocultas de no determinismo: relojes del sistema (cada reproducción ve una marca de tiempo diferente), aritmética de punto flotante (el redondeo varía según la CPU), generación de números aleatorios (no reproducible) y llamadas a API externas (resultados diferentes cada vez). Cuando la reconstrucción del estado depende de cualquiera de estos, la reproducción se vuelve probabilística: podrías obtener el mismo estado, o podrías no hacerlo.
AssetCore elimina el no determinismo a través de restricciones arquitectónicas:
- Los eventos llevan cargas útiles híbridas (delta + estado posterior), y la reproducción utiliza los campos de estado posterior (los valores exactos a establecer, no las operaciones para calcularlos)
- Replay utiliza L1 setters (sin aritmética, sin validación, solo aplicación de estado)
- No hay dependencias externas durante la reproducción (sin llamadas a API, sin lecturas de reloj, sin aleatoriedad)
Lo que esto permite: reproducir cualquier punto en el registro e inspeccionar el estado exacto, reconstruir proyecciones desde cero con confianza, demostrar qué sucedió y cuándo para auditoría. Lo que se sacrifica: no se pueden llamar APIs externas desde las operaciones ni confiar en el tiempo del reloj; todo debe fluir a través del registro de confirmaciones.
Idempotencia
Aplicar el mismo evento dos veces no tiene efecto adicional. Esta es la propiedad que hace que la repetición sea segura después de fallos y caídas de red.
Sin idempotencia, reproducir eventos es peligroso. Si un evento dice “añadir 10 a este saldo”, reproducirlo dos veces añade 20—has corrompido el estado. Si un evento dice “mover la instancia a la posición (3,5)”, reproducirlo puede tener éxito la primera vez y fallar la segunda (ya está allí), causando un comportamiento divergente. Los sistemas que no son idempotentes deben rastrear exactamente qué eventos se han aplicado, lo que introduce una contabilidad compleja y modos de fallo.
AssetCore hace que la repetición sea idempotente por diseño:
- Los eventos llevan el estado final a establecer (no deltas a aplicar)
- La repetición simplemente sobrescribe con ese estado (aplicar “set balance to 50” dos veces resulta en 50, no en 100)
- Seguro para reintentar después de fallos (si no estás seguro de que un evento se aplicó, simplemente aplícalo de nuevo)
Lo que esto permite: recuperación de fallos sin lógica de reanudación compleja, reintentos sin corrupción de estado, confianza en que “reproducir el registro” siempre produce el mismo resultado. Lo que se sacrifica: los eventos son ligeramente más grandes (llevan el estado posterior, no solo deltas), pero la simplicidad operativa vale la pena.
Atomicidad
Todas las operaciones en una transacción tienen éxito o fallan juntas. Esta es la garantía que previene la corrupción parcial del estado.
Sin atomicidad, una falla en la operación 5 de 10 deja las operaciones 1-4 comprometidas y 6-10 no ejecutadas. Su estado es ahora internamente inconsistente: un contenedor creado pero nunca poblado, una transferencia medio ejecutada, una instancia movida pero su referencia padre obsoleta. La depuración requiere reconstruir “lo que debería haber sucedido”, lo cual es a menudo imposible. Los usuarios ven un estado corrupto, las operaciones fallan inesperadamente y la confianza se erosiona.
AssetCore aplica la atomicidad a través de un registro de deshacer:
- Los registros L3 deshacen pasos durante la ejecución (invierten operaciones para cada cambio de estado)
- Las fallas activan el rollback de todos los cambios (reproduce el registro de deshacer en reversa, restaurando el estado exacto anterior)
- No se ven commits parciales (las consultas nunca ven estados intermedios)
La respuesta de error te indica QUÉ operación falló y por qué, pero el estado permanece limpio. Lo que ganas: confianza en que las transacciones fallidas no dejan rastro, no hay necesidad de limpieza manual después de fallos, la consistencia interna es una garantía y no un esfuerzo. Lo que cedes: no puedes “confirmar lo que tuvo éxito y omitir lo que falló”; si alguna operación falla, toda la transacción se revierte. Eso no es un error, es el diseño. Si necesitas un progreso parcial, divide la transacción en confirmaciones más pequeñas con puntos de control explícitos.
Seguridad en caso de fallos
Con un backend de registro de confirmaciones duradero, el sistema se recupera correctamente de los fallos, sin pérdida de datos y sin intervención manual. Esto es lo que hace que AssetCore sea seguro para ejecutar en producción.
La mayoría de los sistemas requieren procedimientos operativos cuidadosos después de un fallo: verificar el estado dañado, reconciliar transacciones en curso, verificar la consistencia entre réplicas y, posiblemente, restaurar desde una copia de seguridad. Estos procedimientos son propensos a errores (los humanos omiten pasos) y consumen mucho tiempo (la recuperación puede tardar minutos u horas). Peor aún, algunas fallas no se pueden recuperar automáticamente; requieren correcciones manuales de datos o aceptar la pérdida de datos.
La arquitectura de AssetCore hace que la recuperación de fallos sea automática y sin pérdida cuando el registro de confirmaciones es duradero:
- El registro de confirmaciones sobrevive a los reinicios cuando está respaldado por un almacenamiento duradero
- Los puntos de control registran el progreso (instantáneas del estado de proyección en posiciones de registro conocidas)
- Replay reconstruye cualquier estado faltante (cargar punto de control, reproducir desde esa posición hasta la cabeza del registro)
Después de un fallo, el daemon de escritura se reanuda en la última posición de punto de control y continúa procesando el registro. Los daemons de lectura recargan sus puntos de control y reproducen hacia adelante. Con un backend duradero, no se pierde ningún estado (el registro tiene todo), no se requiere intervención manual (la recuperación es automática) y no es posible la corrupción (la reproducción es determinista e idempotente). En modos en memoria, la historia es intencionadamente efímera y la recuperación es un reinicio limpio. Lo que se gana: simplicidad operativa, confianza en la recuperación ante desastres, sin páginas a las 3 AM para arreglar un estado corrupto. Lo que se pierde: el tiempo de recuperación escala con el número de eventos desde el último punto de control, pero los puntos de control se toman con frecuencia (configurable, típicamente cada pocos segundos).
Ver también
- Frescura y Repetición - Qué tan “frescos” son los datos leídos
- Transacciones y Operaciones - La unidad atómica de cambio