Zum Inhalt springen

Architektur

Diese Seite ist in Bearbeitung. Inhalte können unvollständig sein oder sich ändern.

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.

SchichtKomponenten
AnwendungLua-Prozesse, Funktionen, Workflows
RuntimeLua-Engine (gopher-lua), 50+ Module
ServicesHTTP, Queue, Storage, Temporal
SystemTopologie, Factory, Functions, Contracts
CoreScheduler, Registry, Dispatcher, EventBus, Relay
InfrastrukturAppContext, 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.

Der Anwendungsstart durchläuft vier Phasen.

Erstellt Kerninfrastruktur bevor Komponenten geladen werden:

KomponenteZweck
AppContextVersiegeltes Dictionary für Komponentenreferenzen
EventBusPub/Sub für Inter-Komponenten-Kommunikation
TranscoderPayload-Serialisierung (JSON, YAML, Lua)
LoggerStrukturiertes Logging mit Event-Streaming
RelayNachrichtenrouting (Node, Router, Mailbox)

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.

Nach dem Laden aller Komponenten:

  1. Dispatcher einfrieren - Sperrt Command-Handler-Registry für lock-freie Lookups
  2. AppContext versiegeln - Keine Schreibzugriffe mehr erlaubt, ermöglicht lock-freie Lesezugriffe
  3. Komponenten starten - Ruft Start() auf jeder Komponente mit Starter-Interface auf

Registry-Einträge (aus YAML-Dateien) werden geladen und validiert:

  1. Einträge aus Projektdateien geparst
  2. Pipeline-Stufen transformieren Einträge (Override, Link, Bytecode)
  3. Services markiert mit auto_start: true starten
  4. Supervisor überwacht registrierte Services

Komponenten sind Go-Services, die am Anwendungslebenszyklus teilnehmen.

PhaseMethodeZweck
LoadLoad(ctx) (ctx, error)Initialisieren und an Kontext anhängen
StartStart(ctx) errorAktiven Betrieb beginnen
StopStop(ctx) errorKontrolliertes Herunterfahren

Komponenten deklarieren Abhängigkeiten. Der Loader baut einen gerichteten azyklischen Graphen und führt in topologischer Reihenfolge aus. Shutdown erfolgt in umgekehrter Reihenfolge.

KomponenteAbhängigkeitenZweck
PIDGenkeineProzess-ID-Generierung
DispatcherPIDGenCommand-Handler-Dispatch
RegistryDispatcherEntry-Speicherung und Versionierung
FinderRegistryEntry-Lookup und Suche
SupervisorRegistryService-Neustartrichtlinien
TopologySupervisorProzess-Eltern/Kind-Baum
LifecycleTopologyService-Lebenszyklus-Management
FactoryLifecycleProzess-Spawning
FunctionsFactoryZustandslose Funktionsaufrufe

Asynchrones Pub/Sub für Inter-Komponenten-Kommunikation.

  • 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
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

Topics haben das Format <system>:<kind>. Die integrierten Systeme veröffentlichen:

SystemKindZweck
registryentry.create, entry.update, entry.delete, entry.accept, entry.rejectEntry-Mutationen
registryregistry.begin, registry.commit, registry.discardTransaktionsgrenzen
processfactory.register, factory.delete, factory.accept, factory.rejectFactory-Registrierung für Process-Kinds
supervisorservice.register, service.remove, service.update, service.start, service.stopService-Lebenszyklus

Versionierte Speicherung für Entry-Definitionen.

  • 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
flowchart LR
YAML[YAML-Dateien] --> Parser
Parser --> Stages[Pipeline-Stufen]
Stages --> Registry
Registry --> Validation
Validation --> Active

Pipeline-Stufen transformieren Einträge:

StufeZweck
OverrideKonfigurations-Overrides anwenden
DisableEinträge nach Muster entfernen
LinkRequirements und Abhängigkeiten auflösen
BytecodeLua zu Bytecode kompilieren
EmbedFSDateisystem-Einträge sammeln

Nachrichtenrouting zwischen Prozessen über Nodes hinweg.

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]
  1. Local - Direkte Zustellung innerhalb desselben Nodes
  2. Peer - Weiterleitung an Peer-Nodes im Cluster
  3. Internode - Routing zu Remote-Nodes via Netzwerk

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

Versiegeltes Dictionary für Komponentenreferenzen.

EigenschaftVerhalten
Vor VersiegelungSingle-Threaded-Schreibzugriffe während Boot
Nach VersiegelungLock-freie Lesezugriffe, Panic bei Schreibzugriff
Duplikat-SchlüsselPanic
TypsicherheitTypisierte Getter-Funktionen

Komponenten hängen Services während der Load-Phase an. Nach Boot-Abschluss wird AppContext für optimale Leseleistung versiegelt.

Das kontrollierte Herunterfahren erfolgt in umgekehrter Abhängigkeitsreihenfolge:

  1. SIGINT/SIGTERM löst Shutdown aus
  2. Supervisor stoppt verwaltete Services
  3. Komponenten mit Stopper-Interface erhalten Stop()
  4. Infrastruktur-Cleanup

Zweites Signal erzwingt sofortigen Exit.