Runtime und Observability mit Aspire
Nachdem Lino Services, Web-Apps und Infrastrukturressourcen generiert hat, hilft Aspire dabei, alles lokal mit Sichtbarkeit auszuführen. Observability ist kein Luxus: Sie zeigt, ob APIs, Datenbanken, Cache, Messaging und Worker gesund sind.
In Anwendungen mit Events, Outbox, Workern, Redis, RabbitMQ und mehreren Modulen erscheinen viele Probleme nicht nur auf dem Bildschirm. Sie erscheinen in Logs, Queues, jobs, migrations, Parametern und Runtime-Ressourcen. Dieser Abschnitt zeigt, wie Sie die Lösung als laufendes System betrachten, nicht nur als generierte Dateien.
Ausführung mit Aspire
Der AppHost bündelt die lokale Ausführung der Lösung. Er startet Services, Web-Apps und Abhängigkeiten wie PostgreSQL, Redis, RabbitMQ und Worker.
dotnet run --project src/Aspire/AppHost/<ProjectName>.AppHost.csproj
Nutzen Sie das Dashboard, um Logs, Variablen, Endpoints und den Ressourcenstatus zu prüfen. Wenn ein Service nicht startet, beginnen Sie beim AppHost und den Abhängigkeiten, die er injiziert.
Aspire macht die lokale Topologie sichtbar: APIs, Web-Apps, Datenbanken, Cache, Message Broker und Worker erscheinen als zusammengehörige Ressourcen. Diese Sicht hilft, Konfigurationsfehler zu finden, die bei manueller Ausführung verborgen blieben, etwa eine falsche connection string, ein fehlender Parameter, ein Service ohne Endpoint oder eine Abhängigkeit, die noch nicht gestartet ist.
- Logs: verfolgen Sie Initialisierungsfehler, Authentifizierungsfehler, Migrations-Probleme und Worker-Meldungen.
- Endpoints: bestätigen Sie Ports, URLs, health checks und Links zu Web-Apps und APIs.
- Parameter: validieren Sie secrets und Variablen, die an jeden Service weitergegeben werden.
- Abhängigkeiten: prüfen Sie, ob Redis, RabbitMQ und die Datenbank bereitgestellt wurden, bevor Sie die Anwendung diagnostizieren.
Datenbankressourcen
Von Lino generierte Services haben normalerweise eigene DbContexts, migrations und connection strings. In modularen Systemen müssen Sie validieren, ob jedes Modul die erwartete Datenbank/das erwartete Schema verwendet und ob migrations am richtigen Ort angewendet wurden.
- Bestätigen Sie connection strings pro Umgebung.
- Führen Sie migrations aus, bevor Sie Flows testen, die von einem neuen Schema abhängen.
- Überwachen Sie Verbindungsfehler und Query-Zeit.
- Vermeiden Sie die Nutzung einer Produktionsdatenbank bei lokaler Ausführung.
In einem einfachen Service begleitet die Datenbank den Service. In einem modularen Service gehört die Datenbank zum Service, aber jedes Modul kann ein eigenes Schema, einen eigenen DbContext, migrations und scripts haben. Diese Trennung muss auch im Betrieb sichtbar sein: Bestätigen Sie beim Anwenden von migrations Service, Modul, provider und Umgebung, bevor Sie ausführen.
Datenbankfehler erscheinen oft als API-Fehler, die Ursache kann aber im AppHost, in der connection string, in einer ausstehenden migration, in einem fehlenden Schema oder in lokalen Zugangsdaten liegen. Daher sollte die Diagnose mit der vollständigen Kette beginnen: Aspire-Parameter, aktive Datenbankressource, angewendete migration, korrekter DbContext und Endpoint, der das erwartete Modul aufruft.
Redis und Cache
Redis kann je nach aktivierten Templates für Cache, temporären Zustand, Tokens, rate limiting oder andere Ressourcen verwendet werden. Cache verbessert die Performance, führt aber Invalidation und eventual consistency ein.
Dokumentieren Sie Schlüssel, Ablaufzeit und Herkunft der Daten. Speichern Sie niemals sensible secrets im Cache, ohne Verschlüsselung, Ablauf und Zugriff zu verstehen.
Wenn das Projekt verteilten Cache verwendet, können mehrere Instanzen Werte teilen, was für horizontale Skalierung nützlich ist. Wenn nur lokaler In-Memory-Cache verwendet wird, hält jeder Prozess seine eigene Kopie. Dieser Unterschied beeinflusst Verhalten in Produktion, Lasttests und Dateninvalidierung.
| Frage | Warum es wichtig ist |
|---|---|
| Woher stammen die gecachten Daten? | Definiert, wie der Wert neu berechnet wird, wenn er abläuft oder invalidiert wird. |
| Welche TTL ist akzeptabel? | Bestimmt, wie lange das System potenziell veraltete Daten toleriert. |
| Ist der Cache pro Tenant, Benutzer oder global? | Verhindert Datenlecks zwischen Kontexten und schlecht modellierte Schlüssel. |
RabbitMQ und Messaging
Messaging trägt Integrations-Events und asynchrone Kommunikation. Mit Outbox hängt die Anwendung nicht davon ab, die Nachricht im selben Moment wie die Transaktion zu veröffentlichen; der Worker kann es erneut versuchen.
- Prüfen Sie die generierten exchanges, Queues und bindings.
- Überwachen Sie festhängende Nachrichten und inaktive Consumer.
- Entwerfen Sie idempotente handlers.
- Nutzen Sie Korrelations-Logs, um den Weg der Nachricht zu verfolgen.
Integrations-Events sind gerade deshalb nützlich, weil der Producer nicht auf alle Consumer warten muss. Das verlagert aber einen Teil der Komplexität in den Betrieb: Nachrichten können sich verzögern, Consumer können fehlschlagen, payloads können sich ändern und handlers können mehr als einmal ausgeführt werden. Die Flow-Dokumentation sollte klar machen, welches Event veröffentlicht wird, wer es konsumiert und welcher lokale Zustand aktualisiert wird.
Shadow Entities hängen von dieser Observability ab. Wenn eine Tenant- oder Benutzer-Entität per Event in andere Module repliziert wird, kann ein Consumer-Fehler die lokale Kopie veraltet lassen. Das System muss ermöglichen, das Event, die Nachricht, den handler und die Aktualisierung in der Datenbank des Consumer-Moduls zu diagnostizieren.
Hangfire Dashboard
Wenn background jobs aktiviert sind, hilft das Hangfire Dashboard dabei, wiederkehrende jobs, Fehler, retries und die Ausführung der Outbox-Verarbeitung zu untersuchen.
Schützen Sie das Dashboard in gemeinsam genutzten Umgebungen. Es zeigt relevante Betriebsinformationen und sollte ohne Authentifizierung und Autorisierung nicht öffentlich sein.
Verwenden Sie das Dashboard als Diagnosewerkzeug, nicht als Ersatz für Logs und Metriken. Es zeigt Queues, Versuche und Ausführungshistorie, aber eine vollständige Untersuchung benötigt weiterhin correlation id, strukturierte Logs und fachlichen Kontext, um zu verstehen, warum ein job fehlgeschlagen ist.
- Retries: prüfen Sie, ob der Fehler transient ist oder ob der job dauerhaft weiter fehlschlagen wird.
- Wiederkehrende jobs: bestätigen Sie Intervall, Batch und durchschnittliche Ausführungsdauer.
- Outbox: beobachten Sie festhängende Nachrichten, Wiederverarbeitung und handlers mit Exceptions.
- Sicherheit: beschränken Sie den Zugriff, weil payloads und Fehler sensible Daten offenlegen können.
Worker und Hintergrundverarbeitung
Worker führen Aufgaben aus, die HTTP-Anfragen nicht blockieren dürfen: Senden von Nachrichten, Outbox-Verarbeitung, Bereinigung, Synchronisierung und externe Integrationen.
- Verwenden Sie zum Volumen passende Batches.
- Definieren Sie retries und Fehlerbehandlung.
- Protokollieren Sie Fehler mit ausreichend Kontext für Wiederverarbeitung.
- Verbergen Sie permanente Fehler nicht in generischen Logs.
Wenn Sie einen Worker hinzufügen, definieren Sie auch Frequenz, Batchgröße, Verhalten bei Fehlern und Auswirkungen auf die Domain. Ein Worker, der alle paar Sekunden 100 Datensätze liest, hat ein anderes Betriebsverhalten als ein täglicher job; beide müssen entsprechend dem realen Volumen beobachtet und dimensioniert werden.
Führen Sie nichts im Hintergrund aus, das dem Benutzer sofort antworten muss. Verwenden Sie Worker für nachgelagerte Aufgaben, Integrationen, Benachrichtigungen, Wiederverarbeitung und Wartung. Wenn der Use Case vom Ergebnis abhängt, um die Transaktion abzuschließen, behandeln Sie ihn als synchronen Flow oder modellieren Sie einen für den Benutzer sichtbaren Zwischenzustand.
