Pular para o conteúdo

Arquitetura

Esta página está em construção. O conteúdo pode estar incompleto ou mudar.

Wippy é um sistema em camadas construído em Go. Componentes inicializam em ordem de dependência, comunicam-se através de um barramento de eventos e executam processos Lua via um scheduler de work-stealing.

CamadaComponentes
AplicaçãoProcessos Lua, funções, workflows
RuntimeMotor Lua (gopher-lua), 50+ módulos
ServiçosHTTP, Queue, Storage, Temporal
SistemaTopology, Factory, Functions, Contracts
NúcleoScheduler, Registry, Dispatcher, EventBus, Relay
InfraestruturaAppContext, Logger, Transcoder

Cada camada depende apenas das camadas abaixo dela. A camada Núcleo fornece primitivas fundamentais, enquanto Serviços constroem abstrações de nível mais alto.

A inicialização da aplicação prossegue em quatro fases.

Cria infraestrutura central antes de qualquer componente carregar:

ComponentePropósito
AppContextDicionário selado para referências de componentes
EventBusPub/sub para comunicação entre componentes
TranscoderSerialização de payload (JSON, YAML, Lua)
LoggerLogging estruturado com streaming de eventos
RelayRoteamento de mensagens (Node, Router, Mailbox)

O Loader resolve dependências via ordenação topológica e carrega componentes nível por nível. Componentes no mesmo nível carregam em paralelo.

Os componentes core (PIDGen, Dispatcher, Registry, Finder, Supervisor) inicializam primeiro, seguidos pelos componentes de sistema (Topology, Lifecycle, Factory, Functions, Contracts). Os níveis concretos são calculados em tempo de execução a partir do grafo de dependências, então a ordenação se adapta à medida que componentes são adicionados ou removidos.

Cada componente se anexa ao contexto durante Load, disponibilizando serviços para componentes dependentes.

Após todos os componentes carregarem:

  1. Congelar Dispatcher - Bloqueia registro de handlers de comando para lookups sem lock
  2. Selar AppContext - Nenhuma escrita mais permitida, habilita leituras sem lock
  3. Iniciar Componentes - Chama Start() em cada componente com interface Starter

Entradas do registro (de arquivos YAML) são carregadas e validadas:

  1. Entradas parseadas dos arquivos do projeto
  2. Estágios de pipeline transformam entradas (override, link, bytecode)
  3. Serviços marcados auto_start: true começam a executar
  4. Supervisor monitora serviços registrados

Componentes são serviços Go que participam do ciclo de vida da aplicação.

FaseMétodoPropósito
LoadLoad(ctx) (ctx, error)Inicializar e anexar ao contexto
StartStart(ctx) errorIniciar operação ativa
StopStop(ctx) errorShutdown gracioso

Componentes declaram dependências. O loader constrói um grafo acíclico direcionado e executa em ordem topológica. Shutdown ocorre em ordem reversa.

ComponenteDependênciasPropósito
PIDGennenhumaGeração de ID de processo
DispatcherPIDGenDespacho de handlers de comando
RegistryDispatcherArmazenamento e versionamento de entradas
FinderRegistryLookup e busca de entradas
SupervisorRegistryPolíticas de reinício de serviço
TopologySupervisorÁrvore pai/filho de processos
LifecycleTopologyGerenciamento de ciclo de vida de serviços
FactoryLifecycleSpawn de processos
FunctionsFactoryChamadas de funções stateless

Pub/sub assíncrono para comunicação entre componentes.

  • Goroutine única de dispatcher processa todos os eventos
  • Entrega de ações baseada em fila previne bloqueio de publishers
  • Pattern matching suporta tópicos exatos e wildcards (*)
  • Ciclo de vida baseado em contexto vincula inscrições a cancelamento
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

Os tópicos têm o formato <system>:<kind>. Os sistemas integrados publicam:

SistemaKindPropósito
registryentry.create, entry.update, entry.delete, entry.accept, entry.rejectMutações de entradas
registryregistry.begin, registry.commit, registry.discardLimites de transação
processfactory.register, factory.delete, factory.accept, factory.rejectRegistro de factory para tipos de processo
supervisorservice.register, service.remove, service.update, service.start, service.stopCiclo de vida de serviço

Armazenamento versionado para definições de entradas.

  • Estado Versionado - Cada mutação cria nova versão
  • Histórico - Histórico em SQLite para trilha de auditoria
  • Observação - Observar entradas específicas para mudanças
  • Orientado a Eventos - Publica eventos em mutações
flowchart LR
YAML[YAML Files] --> Parser
Parser --> Stages[Pipeline Stages]
Stages --> Registry
Registry --> Validation
Validation --> Active

Estágios de pipeline transformam entradas:

EstágioPropósito
OverrideAplicar overrides de config
DisableRemover entradas por padrão
LinkResolver requirements e dependências
BytecodeCompilar Lua para bytecode
EmbedFSColetar entradas de filesystem

Roteamento de mensagens entre processos através de nós.

flowchart LR
subgraph Router
Local[Local Node] --> Peer[Peer Nodes]
Peer --> Inter[Internode]
end
Local -.- L[Same process]
Peer -.- P[Same cluster]
Inter -.- I[Remote]
  1. Local - Entrega direta dentro do mesmo nó
  2. Peer - Encaminhar para nós peer no cluster
  3. Internode - Rotear para nós remotos via rede

Cada nó tem uma mailbox com pool de workers:

  • Hashing FNV-1a atribui remetentes a workers
  • Preserva ordenação de mensagens por remetente
  • Workers processam mensagens concorrentemente
  • Back-pressure quando fila enche

Dicionário selado para referências de componentes.

PropriedadeComportamento
Antes de selarEscritas de thread única durante a inicialização
Após selarLeituras sem lock, panic em escrita
Chaves duplicadasPanic
Type safetyFunções getter tipadas

Componentes anexam serviços durante a fase Load. Após boot completar, AppContext é selado para performance ótima de leitura.

Shutdown gracioso prossegue em ordem reversa de dependência:

  1. SIGINT/SIGTERM aciona shutdown
  2. Supervisor para serviços gerenciados
  3. Componentes com interface Stopper recebem Stop()
  4. Limpeza de infraestrutura

Segundo sinal força saída imediata.