Architektur
Wippy ist ein geschichtetes System, das auf Go aufgebaut ist. Komponenten initialisieren sich in Abhängigkeitsreihenfolge, kommunizieren über einen Event-Bus und führen Lua-Prozesse über einen Work-Stealing-Scheduler aus.
Schichten
| Schicht | Komponenten |
|---|---|
| Anwendung | Lua-Prozesse, Funktionen, Workflows |
| Runtime | Lua-Engine (gopher-lua), 50+ Module |
| Services | HTTP, Queue, Storage, Temporal |
| System | Topologie, Factory, Functions, Contracts |
| Core | Scheduler, Registry, Dispatcher, EventBus, Relay |
| Infrastruktur | AppContext, Logger, Transcoder |
Jede Schicht hängt nur von den Schichten darunter ab. Die Core-Schicht stellt fundamentale Primitive bereit, während Services höhere Abstraktionen darauf aufbauen.
Boot-Sequenz
Der Anwendungsstart durchläuft vier Phasen.
Phase 1: Infrastruktur
Erstellt Kerninfrastruktur bevor Komponenten geladen werden:
| Komponente | Zweck |
|---|---|
| AppContext | Versiegeltes Dictionary für Komponentenreferenzen |
| EventBus | Pub/Sub für Inter-Komponenten-Kommunikation |
| Transcoder | Payload-Serialisierung (JSON, YAML, Lua) |
| Logger | Strukturiertes Logging mit Event-Streaming |
| Relay | Nachrichtenrouting (Node, Router, Mailbox) |
Phase 2: Komponentenladung
Der Loader löst Abhängigkeiten via topologischer Sortierung auf und lädt Komponenten Level für Level. Komponenten auf demselben Level laden parallel.
Core-Komponenten (PIDGen, Dispatcher, Registry, Finder, Supervisor) initialisieren zuerst, gefolgt von Systemkomponenten (Topology, Lifecycle, Factory, Functions, Contracts). Konkrete Level werden zur Laufzeit aus dem Abhängigkeitsgraphen berechnet, sodass sich die Reihenfolge anpasst, wenn Komponenten hinzugefügt oder entfernt werden.
Jede Komponente hängt sich während Load an den Kontext an, wodurch Services für abhängige Komponenten verfügbar werden.
Phase 3: Aktivierung
Nach dem Laden aller Komponenten:
- Dispatcher einfrieren - Sperrt Command-Handler-Registry für lock-freie Lookups
- AppContext versiegeln - Keine Schreibzugriffe mehr erlaubt, ermöglicht lock-freie Lesezugriffe
- Komponenten starten - Ruft
Start()auf jeder Komponente mitStarter-Interface auf
Phase 4: Entry-Ladung
Registry-Einträge (aus YAML-Dateien) werden geladen und validiert:
- Einträge aus Projektdateien geparst
- Pipeline-Stufen transformieren Einträge (Override, Link, Bytecode)
- Services markiert mit
auto_start: truestarten - Supervisor überwacht registrierte Services
Komponenten
Komponenten sind Go-Services, die am Anwendungslebenszyklus teilnehmen.
Lebenszyklusphasen
| Phase | Methode | Zweck |
|---|---|---|
| Load | Load(ctx) (ctx, error) |
Initialisieren und an Kontext anhängen |
| Start | Start(ctx) error |
Aktiven Betrieb beginnen |
| Stop | Stop(ctx) error |
Kontrolliertes Herunterfahren |
Komponenten deklarieren Abhängigkeiten. Der Loader baut einen gerichteten azyklischen Graphen und führt in topologischer Reihenfolge aus. Shutdown erfolgt in umgekehrter Reihenfolge.
Standardkomponenten
| Komponente | Abhängigkeiten | Zweck |
|---|---|---|
| PIDGen | keine | Prozess-ID-Generierung |
| Dispatcher | PIDGen | Command-Handler-Dispatch |
| Registry | Dispatcher | Entry-Speicherung und Versionierung |
| Finder | Registry | Entry-Lookup und Suche |
| Supervisor | Registry | Service-Neustartrichtlinien |
| Topology | Supervisor | Prozess-Eltern/Kind-Baum |
| Lifecycle | Topology | Service-Lebenszyklus-Management |
| Factory | Lifecycle | Prozess-Spawning |
| Functions | Factory | Zustandslose Funktionsaufrufe |
Event-Bus
Asynchrones Pub/Sub für Inter-Komponenten-Kommunikation.
Design
- Einzelne Dispatcher-Goroutine verarbeitet alle Events
- Queue-basierte Action-Zustellung verhindert Publisher-Blockierung
- Pattern-Matching unterstützt exakte Topics und Wildcards (
*) - Kontextbasierter Lebenszyklus bindet Subscriptions an Cancellation
Event-Fluss
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
Gängige Topics
Topics haben das Format <system>:<kind>. Die integrierten Systeme veröffentlichen:
| System | Kind | Zweck |
|---|---|---|
registry |
entry.create, entry.update, entry.delete, entry.accept, entry.reject |
Entry-Mutationen |
registry |
registry.begin, registry.commit, registry.discard |
Transaktionsgrenzen |
process |
factory.register, factory.delete, factory.accept, factory.reject |
Factory-Registrierung für Process-Kinds |
supervisor |
service.register, service.remove, service.update, service.start, service.stop |
Service-Lebenszyklus |
Registry
Versionierte Speicherung für Entry-Definitionen.
Features
- Versionierter Zustand - Jede Mutation erstellt neue Version
- History - SQLite-gestützte Historie für Audit-Trail
- Beobachtung - Spezifische Einträge auf Änderungen beobachten
- Ereignisgesteuert - Publiziert Events bei Mutationen
Entry-Lebenszyklus
flowchart LR
YAML[YAML-Dateien] --> Parser
Parser --> Stages[Pipeline-Stufen]
Stages --> Registry
Registry --> Validation
Validation --> Active
Pipeline-Stufen transformieren Einträge:
| Stufe | Zweck |
|---|---|
| Override | Konfigurations-Overrides anwenden |
| Disable | Einträge nach Muster entfernen |
| Link | Requirements und Abhängigkeiten auflösen |
| Bytecode | Lua zu Bytecode kompilieren |
| EmbedFS | Dateisystem-Einträge sammeln |
Relay
Nachrichtenrouting zwischen Prozessen über Nodes hinweg.
Drei-Stufen-Routing
flowchart LR
subgraph Router
Local[Local Node] --> Peer[Peer Nodes]
Peer --> Inter[Internode]
end
Local -.- L[Selber Prozess]
Peer -.- P[Selber Cluster]
Inter -.- I[Remote]
- Local - Direkte Zustellung innerhalb desselben Nodes
- Peer - Weiterleitung an Peer-Nodes im Cluster
- Internode - Routing zu Remote-Nodes via Netzwerk
Mailbox
Jeder Node hat eine Mailbox mit Worker-Pool:
- FNV-1a-Hashing weist Sender Workern zu
- Erhält Per-Sender-Nachrichtenreihenfolge
- Worker verarbeiten Nachrichten parallel
- Back-Pressure wenn Queue voll
AppContext
Versiegeltes Dictionary für Komponentenreferenzen.
| Eigenschaft | Verhalten |
|---|---|
| Vor Versiegelung | Single-Threaded-Schreibzugriffe während Boot |
| Nach Versiegelung | Lock-freie Lesezugriffe, Panic bei Schreibzugriff |
| Duplikat-Schlüssel | Panic |
| Typsicherheit | Typisierte Getter-Funktionen |
Komponenten hängen Services während der Load-Phase an. Nach Boot-Abschluss wird AppContext für optimale Leseleistung versiegelt.
Shutdown
Das kontrollierte Herunterfahren erfolgt in umgekehrter Abhängigkeitsreihenfolge:
- SIGINT/SIGTERM löst Shutdown aus
- Supervisor stoppt verwaltete Services
- Komponenten mit
Stopper-Interface erhaltenStop() - Infrastruktur-Cleanup
Zweites Signal erzwingt sofortigen Exit.
Siehe auch
- Scheduler - Prozessausführung
- Event-Bus - Pub/Sub-System
- Registry - Zustandsverwaltung
- Command-Dispatch - Yield-Behandlung