Arquitetura
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.
Esta é uma referência de implementação. Os diagramas e tipos Go descrevem internals do runtime, e não entradas do registro da aplicação ou APIs de extensão.
Camadas
| Camada | Componentes |
|---|---|
| Aplicação | Processos Lua, funções, workflows |
| Runtime | Motor Lua (gopher-lua), 40+ módulos |
| Serviços | HTTP, Queue, Storage, Temporal |
| Sistema | Topology, Factory, Functions, Contracts |
| Núcleo | Scheduler, Registry, Dispatcher, EventBus, Relay |
| Infraestrutura | AppContext, 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.
Sequência de Boot
A inicialização da aplicação prossegue em quatro fases.
Fase 1: Infraestrutura
Cria infraestrutura central antes de qualquer componente carregar:
| Componente | Propósito |
|---|---|
| AppContext | Dicionário selado para referências de componentes |
| EventBus | Pub/sub para comunicação entre componentes |
| Transcoder | Serialização de payload (JSON, YAML, Lua) |
| Logger | Logging estruturado com streaming de eventos |
| Relay | Roteamento de mensagens (Node, Router, Mailbox) |
Fase 2: Carregamento de Componentes
O Loader resolve dependências via ordenação topológica e carrega componentes nível por nível, um componente por vez.
As arestas de dependência determinam os níveis; grupos de pacotes como Core e System não impõem uma ordem global separada. Portanto, componentes sem uma aresta de dependência podem ficar no mesmo nível, independentemente do grupo de pacotes.
Cada componente se anexa ao contexto durante Load, disponibilizando serviços para componentes dependentes.
Fase 3: Ativação
Depois que todos os componentes são carregados:
- Iniciar serviços do runtime — Chama
StartRuntimeServices(ctx) - Congelar o Dispatcher — Bloqueia o registro de handlers de comandos para consultas sem lock
- Selar o AppContext — Impede novas escritas e habilita leituras sem lock
- Iniciar componentes — Chama
Start()em cada componente que implementaStarter
Fase 4: Carregamento de Entradas
As entradas do registro provenientes dos manifests _index.json, _index.yaml e _index.yml do projeto são carregadas e validadas:
- Entradas parseadas dos arquivos do projeto
- Estágios de pipeline transformam entradas (override, link, bytecode)
- Serviços marcados
auto_start: truecomeçam a executar - Supervisor monitora serviços registrados
Componentes
Componentes são serviços Go que participam do ciclo de vida da aplicação.
Fases do Ciclo de Vida
| Fase | Método | Propósito |
|---|---|---|
| Load | Load(ctx) (ctx, error) |
Inicializar e anexar ao contexto |
| Start | Start(ctx) error |
Iniciar operação ativa |
| Stop | Stop(ctx) error |
Encerramento gracioso |
Os componentes declaram dependências. O carregador constrói um grafo acíclico direcionado e executa em ordem topológica. O encerramento ocorre em ordem reversa.
Componentes Padrão
| Componente | Dependências | Propósito |
|---|---|---|
| PIDGen | nenhuma | Geração de ID de processo |
| Dispatcher | PIDGen | Despacho de handlers de comando |
| Registry | Artifact | Armazenamento e versionamento de entradas |
| Finder | Registry | Lookup e busca de entradas |
| Supervisor | Registry | Políticas de reinício de serviço |
| Topology | nenhuma | Árvore pai/filho de processos |
| Lifecycle | Topology | Gerenciamento de ciclo de vida de serviços |
| Factory | nenhuma | Criação de processos |
| Functions | Registry | Execução de funções em pool |
Barramento de eventos :id=event-bus
Pub/sub assíncrono para comunicação entre componentes.
Design
- Goroutine única de dispatcher processa todos os eventos
- Publishers enfileiram ações sem aguardar a entrega aos subscribers
- O pattern matching aceita valores exatos,
*,**e alternância de segmentos - Ciclo de vida baseado em contexto vincula inscrições a cancelamento
Fluxo de Eventos
sequenceDiagram
participant P as Publisher
participant B as EventBus
participant S as Subscribers
P->>B: Send(ctx, Event)
B->>B: Match patterns
B->>S: Deliver on subscriber channel
S->>S: Execute callback
Tópicos Comuns
Cada evento carrega um System e um Kind. Os sistemas integrados publicam:
| Sistema | Tipo | Propósito |
|---|---|---|
registry |
entry.create, entry.update, entry.delete, entry.accept, entry.reject |
Mutações de entradas |
registry |
registry.begin, registry.commit, registry.discard |
Limites de transação |
process |
factory.register, factory.delete, factory.accept, factory.reject |
Registro de factory para tipos de processo |
supervisor |
service.register, service.remove, service.update, service.start, service.stop |
Ciclo de vida de serviço |
Registry
Armazenamento versionado para definições de entradas.
Recursos
- Estado Versionado - Cada mutação cria nova versão
- Histórico - Histórico em SQLite para trilha de auditoria
- Orientado a Eventos - Publica eventos em mutações
Ciclo de Vida de Entrada
flowchart LR
YAML[YAML Files] --> Parser
Parser --> Stages[Pipeline Stages]
Stages --> Registry
Registry --> Validation
Validation --> Active
Estágios de pipeline transformam entradas:
| Estágio | Propósito |
|---|---|
| Override | Aplicar overrides de config |
| Desativar | Remover entradas por padrão |
| Link | Resolver requirements e dependências |
| Bytecode | Compilar Lua para bytecode |
| EmbedFS | Coletar entradas de filesystem |
Relay
Roteamento de mensagens entre processos através de nós.
Roteamento de Três Níveis
flowchart LR
subgraph Router
Local[Local Node] --> Peer[Registered Peers]
Peer --> Inter[Internode]
end
Local -.- L[Este nó]
Peer -.- P[Receptor peer registrado]
Inter -.- I[Outros nós do cluster]
- Local - Entrega direta dentro do mesmo nó
- Peer - Entregar a um receptor registrado para aquele ID de nó (um peer externo, como um worker do Temporal)
- Internode - Recorrer ao transporte internode do cluster, instalado pelo componente de cluster após o boot
Mailbox
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
AppContext
Dicionário selado para referências de componentes.
| Propriedade | Comportamento |
|---|---|
| Antes de selar | Escritas de thread única durante a inicialização |
| Após selar | Leituras sem lock, panic em escrita |
| Chaves duplicadas | Panic |
| Segurança de tipos | Funções de acesso tipadas |
Os componentes anexam serviços durante a fase Load. Quando o boot termina, o AppContext é selado, permitindo leituras sem lock e impedindo novas escritas.
Encerramento :id=shutdown
Encerramento gracioso prossegue em ordem reversa de dependência:
- SIGINT/SIGTERM aciona shutdown
- Supervisor para serviços gerenciados
- Componentes com interface
StopperrecebemStop() - Limpeza de infraestrutura
Segundo sinal força saída imediata.
Consulte também
- Scheduler — Execução de processos
- Event bus — Sistema pub/sub
- Registro — Gerenciamento de estado
- Despacho de comandos — Tratamento de yields