Ir al contenido

Arquitectura

Esta página está en progreso. El contenido puede estar incompleto o cambiar.

Wippy es un sistema de capas construido en Go. Los componentes se inicializan en orden de dependencias, se comunican a través de un event bus, y ejecutan procesos Lua vía un scheduler de work-stealing.

CapaComponentes
ApplicationProcesos Lua, funciones, workflows
RuntimeMotor Lua (gopher-lua), 50+ módulos
ServicesHTTP, Queue, Storage, Temporal
SystemTopology, Factory, Functions, Contracts
CoreScheduler, Registry, Dispatcher, EventBus, Relay
InfrastructureAppContext, Logger, Transcoder

Cada capa depende solo de capas debajo de ella. La capa Core proporciona primitivos fundamentales, mientras Services construye abstracciones de nivel más alto encima.

El startup de la aplicación procede a través de cuatro fases.

Crea infraestructura core antes de que cualquier componente cargue:

ComponentePropósito
AppContextDiccionario sellado para referencias de componentes
EventBusPub/sub para comunicación entre componentes
TranscoderSerialización de payload (JSON, YAML, Lua)
LoggerLogging estructurado con streaming de eventos
RelayRouting de mensajes (Node, Router, Mailbox)

El Loader resuelve dependencias vía ordenamiento topológico y carga componentes nivel por nivel. Componentes en el mismo nivel cargan en paralelo.

Los componentes core (PIDGen, Dispatcher, Registry, Finder, Supervisor) se inicializan primero, seguidos por los componentes de sistema (Topology, Lifecycle, Factory, Functions, Contracts). Los niveles concretos se calculan en tiempo de ejecución a partir del grafo de dependencias, por lo que el orden se adapta a medida que se añaden o eliminan componentes.

Cada componente se adjunta al contexto durante Load, haciendo servicios disponibles a componentes dependientes.

Después de que todos los componentes cargan:

  1. Freeze Dispatcher - Bloquea registry de handlers de comandos para lookups sin lock
  2. Seal AppContext - No más escrituras permitidas, habilita lecturas sin lock
  3. Start Components - Llama Start() en cada componente con interfaz Starter

Las entradas de registry (de archivos YAML) son cargadas y validadas:

  1. Entradas parseadas de archivos de proyecto
  2. Etapas de pipeline transforman entradas (override, link, bytecode)
  3. Servicios marcados auto_start: true comienzan a ejecutar
  4. Supervisor monitorea servicios registrados

Los componentes son servicios Go que participan en el ciclo de vida de la aplicación.

FaseMétodoPropósito
LoadLoad(ctx) (ctx, error)Inicializar y adjuntar al contexto
StartStart(ctx) errorComenzar operación activa
StopStop(ctx) errorApagado graceful

Los componentes declaran dependencias. El loader construye un grafo acíclico dirigido y ejecuta en orden topológico. El shutdown ocurre en orden reverso.

ComponenteDependenciasPropósito
PIDGenningunaGeneración de ID de proceso
DispatcherPIDGenDespacho de handlers de comandos
RegistryDispatcherAlmacenamiento y versionado de entradas
FinderRegistryLookup y búsqueda de entradas
SupervisorRegistryPolíticas de reinicio de servicios
TopologySupervisorÁrbol padre/hijo de procesos
LifecycleTopologyGestión de ciclo de vida de servicios
FactoryLifecycleGeneración de procesos
FunctionsFactoryLlamadas a funciones stateless

Pub/sub asíncrono para comunicación entre componentes.

  • Una sola goroutine dispatcher procesa todos los eventos
  • Entrega de acciones basada en cola previene bloqueo de publishers
  • Pattern matching soporta tópicos exactos y wildcards (*)
  • Ciclo de vida basado en contexto vincula suscripciones a cancelación
sequenceDiagram
participant P as Publisher
participant B as EventBus
participant S as Subscribers
P->>B: Publish(topic, data)
B->>B: Match patterns
B->>S: Queue action
S->>S: Execute callback

Los tópicos tienen el formato <system>:<kind>. Los sistemas integrados publican:

SistemaKindPropósito
registryentry.create, entry.update, entry.delete, entry.accept, entry.rejectMutaciones de entradas
registryregistry.begin, registry.commit, registry.discardLímites de transacción
processfactory.register, factory.delete, factory.accept, factory.rejectRegistro de factory para tipos de proceso
supervisorservice.register, service.remove, service.update, service.start, service.stopCiclo de vida de servicio

Almacenamiento versionado para definiciones de entradas.

  • Versioned State - Cada mutación crea nueva versión
  • History - Historial respaldado por SQLite para audit trail
  • Observation - Watch de entradas específicas para cambios
  • Event-driven - Publica eventos en mutaciones
flowchart LR
YAML[YAML Files] --> Parser
Parser --> Stages[Pipeline Stages]
Stages --> Registry
Registry --> Validation
Validation --> Active

Etapas de pipeline transforman entradas:

EtapaPropósito
OverrideAplicar overrides de config
DisableRemover entradas por patrón
LinkResolver requirements y dependencias
BytecodeCompilar Lua a bytecode
EmbedFSRecolectar entradas de filesystem

Routing de mensajes entre procesos a través de nodos.

flowchart LR
subgraph Router
Local[Local Node] --> Peer[Peer Nodes]
Peer --> Inter[Internode]
end
Local -.- L[Mismo proceso]
Peer -.- P[Mismo cluster]
Inter -.- I[Remoto]
  1. Local - Entrega directa dentro del mismo nodo
  2. Peer - Forward a nodos peer en cluster
  3. Internode - Enrutar a nodos remotos vía red

Cada nodo tiene un mailbox con pool de workers:

  • Hashing FNV-1a asigna remitentes a workers
  • Preserva ordenamiento de mensajes por remitente
  • Workers procesan mensajes concurrentemente
  • Back-pressure cuando cola se llena

Diccionario sellado para referencias de componentes.

PropiedadComportamiento
Before sealEscrituras de un solo hilo durante el arranque
After sealLecturas sin lock, panic en escritura
Duplicate keysPanic
Type safetyFunciones getter tipadas

Los componentes adjuntan servicios durante fase Load. Después de que boot completa, AppContext es sellado para rendimiento óptimo de lectura.

El apagado graceful procede en orden reverso de dependencias:

  1. SIGINT/SIGTERM dispara shutdown
  2. Supervisor detiene servicios gestionados
  3. Componentes con interfaz Stopper reciben Stop()
  4. Limpieza de infraestructura

Segunda señal fuerza salida inmediata.